diff options
| author | Andrew Bell <andrew.bell.ia@gmail.com> | 2019-05-15 10:47:03 -0400 |
|---|---|---|
| committer | Andrew Bell <andrew.bell.ia@gmail.com> | 2019-05-15 10:47:03 -0400 |
| commit | 8f268409d37cea329d263e177b83e42f8384d3c7 (patch) | |
| tree | c4d0f3dd19456600f718a6e0c8573577f433549b /src | |
| parent | 886ced02f0aaab5d66d16459435f7447cf976650 (diff) | |
| parent | d67203a6f76a74f5ac029ff052dbcc72e3b59624 (diff) | |
| download | PROJ-8f268409d37cea329d263e177b83e42f8384d3c7.tar.gz PROJ-8f268409d37cea329d263e177b83e42f8384d3c7.zip | |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'src')
183 files changed, 5473 insertions, 3207 deletions
diff --git a/src/4D_api.cpp b/src/4D_api.cpp index 1b3374f3..81e16600 100644 --- a/src/4D_api.cpp +++ b/src/4D_api.cpp @@ -51,6 +51,7 @@ #include "proj/common.hpp" #include "proj/coordinateoperation.hpp" #include "proj/internal/internal.hpp" +#include "proj/internal/io_internal.hpp" using namespace NS_PROJ::internal; @@ -192,6 +193,8 @@ similarly, but prefers the 2D resp. 3D interfaces if available. direction = opposite_direction(direction); if( !P->alternativeCoordinateOperations.empty() ) { + // Do a first pass and select the first coordinate operation whose area + // of use is compatible with the input coordinate int i = 0; for( const auto &alt: P->alternativeCoordinateOperations ) { if( direction == PJ_FWD ) { @@ -223,6 +226,35 @@ similarly, but prefers the 2D resp. 3D interfaces if available. } i ++; } + + // In case we did not find an operation whose area of use is compatible + // with the input coordinate, then goes through again the list, and + // use the first operation that does not require grids. + i = 0; + for( const auto &alt: P->alternativeCoordinateOperations ) { + auto coordOperation = dynamic_cast< + NS_PROJ::operation::CoordinateOperation*>(alt.pj->iso_obj.get()); + if( coordOperation ) { + if( coordOperation->gridsNeeded(P->ctx->cpp_context ? + P->ctx->cpp_context->databaseContext.as_nullable() : + nullptr).empty() ) { + if( P->iCurCoordOp != i ) { + std::string msg("Using coordinate operation "); + msg += alt.name; + pj_log(P->ctx, PJ_LOG_TRACE, msg.c_str()); + P->iCurCoordOp = i; + } + if( direction == PJ_FWD ) { + return pj_fwd4d( coord, alt.pj ); + } + else { + return pj_inv4d( coord, alt.pj ); + } + } + } + i++; + } + proj_errno_set (P, EINVAL); return proj_coord_error (); } @@ -1102,8 +1134,8 @@ PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *source_crs, const char double north_lat = 0.0; const char* name = proj_get_name(op); - if( name && (strstr(name, "Null geographic offset") || - strstr(name, "Null geocentric translation")) ) + if( name && (strstr(name, "Ballpark geographic offset") || + strstr(name, "Ballpark geocentric translation")) ) { // Skip default transformations } @@ -1333,6 +1365,7 @@ static char *path_append (char *buf, const char *app, size_t *buf_size) { pj_dealloc (buf); buf = p; } + assert(buf); /* Only append a semicolon if something's already there */ if (0 != buflen) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 122227bf..48c785a5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,71 +3,77 @@ include(lib_proj.cmake) # configure executable build -option(BUILD_CCT "Build cct (coordinate conversion and transformation tool)" ON) -option(BUILD_CS2CS "Build cs2cs (coordinate systems to coordinate systems translation tool)" ON) -option(BUILD_GEOD "Build geod (computation of geodesic lines)" ON) -option(BUILD_GIE "Build gie (geospatial integrity investigation environment - a PROJ.4 test tool)" ON) -option(BUILD_PROJ "Build proj (cartographic projection tool : latlong <-> projected coordinates)" ON) -option(BUILD_PROJINFO "Build projinfo (SRS and coordinate operation metadata/query tool)" ON) +option(BUILD_CCT + "Build cct (coordinate conversion and transformation tool)" ON) +option(BUILD_CS2CS + "Build cs2cs (coordinate systems to coordinate systems translation tool)" ON) +option(BUILD_GEOD + "Build geod (computation of geodesic lines)" ON) +option(BUILD_GIE + "Build gie (geospatial integrity investigation environment)" ON) +option(BUILD_PROJ + "Build proj (cartographic projection tool)" ON) +option(BUILD_PROJINFO + "Build projinfo (SRS and coordinate operation metadata/query tool)" ON) if(NOT MSVC) - if (NOT APPLE) + if(NOT APPLE) # Use relative path so that package is relocatable set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${LIBDIR}") - else () - set (CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LIBDIR}") + else() + set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LIBDIR}") # TO DO: cmake 2.8.12 introduces a way to make the install tree # relocatable with OSX via # (1) set(CMAKE_MACOSX_RPATH ON) and # (2) setting the INSTALL_RPATH property on the executables to # "@loader_path/../${LIBDIR}" - endif () + endif() -else () +else() # Linking to setargv.obj enables wildcard globbing for the # command line utilities, when compiling with MSVC - # https://docs.microsoft.com/da-dk/cpp/c-language/expanding-wildcard-arguments + # https://docs.microsoft.com/cpp/c-language/expanding-wildcard-arguments set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} setargv.obj") -endif () +endif() if(BUILD_CCT) - include(bin_cct.cmake) - set(BIN_TARGETS ${BIN_TARGETS} cct) -endif(BUILD_CCT) + include(bin_cct.cmake) + set(BIN_TARGETS ${BIN_TARGETS} cct) +endif() if(BUILD_CS2CS) - include(bin_cs2cs.cmake) - set(BIN_TARGETS ${BIN_TARGETS} cs2cs) -endif(BUILD_CS2CS) + include(bin_cs2cs.cmake) + set(BIN_TARGETS ${BIN_TARGETS} cs2cs) +endif() if(BUILD_GEOD) include(bin_geod.cmake) include(bin_geodtest.cmake) set(BIN_TARGETS ${BIN_TARGETS} geod) -endif(BUILD_GEOD) +endif() if(BUILD_PROJ) include(bin_proj.cmake) set(BIN_TARGETS ${BIN_TARGETS} binproj) -endif(BUILD_PROJ) +endif() if(BUILD_PROJINFO) include(bin_projinfo.cmake) set(BIN_TARGETS ${BIN_TARGETS} binprojinfo) -endif(BUILD_PROJINFO) +endif() if(BUILD_GIE) - include(bin_gie.cmake) - set(BIN_TARGETS ${BIN_TARGETS} gie) -endif(BUILD_GIE) + include(bin_gie.cmake) + set(BIN_TARGETS ${BIN_TARGETS} gie) +endif() -if (MSVC OR CMAKE_CONFIGURATION_TYPES) +if(MSVC OR CMAKE_CONFIGURATION_TYPES) if(BIN_TARGETS) # Add _d suffix for your debug versions of the tools - set_target_properties (${BIN_TARGETS} PROPERTIES + set_target_properties(${BIN_TARGETS} PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) - endif(BIN_TARGETS) -endif () + endif() +endif() diff --git a/src/Makefile.am b/src/Makefile.am index b62a11b0..aed5a393 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,7 +8,7 @@ check_PROGRAMS = geodtest AM_CPPFLAGS = -DPROJ_LIB=\"$(pkgdatadir)\" \ -DMUTEX_@MUTEX_SETTING@ @JNI_INCLUDE@ -I$(top_srcdir)/include @SQLITE3_CFLAGS@ -AM_CXXFLAGS = @CXX_WFLAGS@ @FLTO_FLAG@ -DPROJ_COMPILATION +AM_CXXFLAGS = @CXX_WFLAGS@ @FLTO_FLAG@ include_HEADERS = proj.h proj_experimental.h proj_constants.h proj_api.h geodesic.h \ org_proj4_PJ.h proj_symbol_rename.h @@ -16,11 +16,11 @@ include_HEADERS = proj.h proj_experimental.h proj_constants.h proj_api.h geodesi EXTRA_DIST = bin_cct.cmake bin_gie.cmake bin_cs2cs.cmake \ bin_geod.cmake bin_proj.cmake bin_projinfo.cmake \ lib_proj.cmake CMakeLists.txt bin_geodtest.cmake tests/geodtest.cpp \ - wkt1_grammar.y wkt2_grammar.y apps/emess.h + wkt1_grammar.y wkt2_grammar.y apps/emess.h apps/utils.h -proj_SOURCES = apps/proj.cpp apps/emess.cpp +proj_SOURCES = apps/proj.cpp apps/emess.cpp apps/utils.cpp projinfo_SOURCES = apps/projinfo.cpp -cs2cs_SOURCES = apps/cs2cs.cpp apps/emess.cpp +cs2cs_SOURCES = apps/cs2cs.cpp apps/emess.cpp apps/utils.cpp cct_SOURCES = apps/cct.cpp apps/proj_strtod.cpp apps/proj_strtod.h apps/optargpm.h geod_SOURCES = apps/geod.cpp apps/geod_set.cpp apps/geod_interface.cpp apps/geod_interface.h apps/emess.cpp @@ -42,7 +42,7 @@ geodtest_LDADD = libproj.la lib_LTLIBRARIES = libproj.la -libproj_la_LDFLAGS = -no-undefined -version-info 15:0:0 +libproj_la_LDFLAGS = -no-undefined -version-info 16:0:1 libproj_la_LIBADD = @SQLITE3_LIBS@ libproj_la_SOURCES = \ @@ -173,6 +173,7 @@ libproj_la_SOURCES = \ conversions/cart.cpp \ conversions/geoc.cpp \ conversions/geocent.cpp \ + conversions/noop.cpp \ conversions/unitconvert.cpp \ \ transformations/affine.cpp \ diff --git a/src/apply_gridshift.cpp b/src/apply_gridshift.cpp index c7070432..fcd9fa01 100644 --- a/src/apply_gridshift.cpp +++ b/src/apply_gridshift.cpp @@ -34,7 +34,6 @@ #include <stdio.h> #include <string.h> -#include "proj_internal.h" #include "proj.h" #include "proj_internal.h" @@ -59,7 +58,10 @@ int pj_apply_gridshift( projCtx ctx, const char *nadgrids, int inverse, gridlist = pj_gridlist_from_nadgrids( ctx, nadgrids, &grid_count ); if( gridlist == nullptr || grid_count == 0 ) + { + pj_dalloc( gridlist ); return ctx->last_errno; + } ret = pj_apply_gridshift_3( ctx, gridlist, grid_count, inverse, point_count, point_offset, x, y, z ); diff --git a/src/apply_vgridshift.cpp b/src/apply_vgridshift.cpp index 61e0c528..377e36e0 100644 --- a/src/apply_vgridshift.cpp +++ b/src/apply_vgridshift.cpp @@ -28,23 +28,23 @@ #define PJ_LIB__ +#include <assert.h> #include <stdio.h> #include <string.h> #include "proj_math.h" #include "proj_internal.h" -#include "proj_internal.h" -static int is_nodata(float value) +static int is_nodata(float value, double vmultiplier) { /* nodata? */ /* GTX official nodata value if -88.88880f, but some grids also */ /* use other big values for nodata (e.g naptrans2008.gtx has */ /* nodata values like -2147479936), so test them too */ - return value > 1000 || value < -1000 || value == -88.88880f; + return value * vmultiplier > 1000 || value * vmultiplier < -1000 || value == -88.88880f; } -static double read_vgrid_value( PJ *defn, PJ_LP input, int *gridlist_count_p, PJ_GRIDINFO **tables, struct CTABLE *ct) { +static double read_vgrid_value( PJ *defn, PJ_LP input, double vmultiplier, int *gridlist_count_p, PJ_GRIDINFO **tables, struct CTABLE *ct) { int itable = 0; double value = HUGE_VAL; double grid_x, grid_y; @@ -63,9 +63,19 @@ static double read_vgrid_value( PJ *defn, PJ_LP input, int *gridlist_count_p, PJ ct = gi->ct; - /* skip tables that don't match our point at all. */ - if( ct->ll.phi > input.phi || ct->ll.lam > input.lam - || ct->ll.phi + (ct->lim.phi-1) * ct->del.phi < input.phi + /* skip tables that don't match our point at all (latitude check). */ + if( ct->ll.phi > input.phi + || ct->ll.phi + (ct->lim.phi-1) * ct->del.phi < input.phi ) + continue; + + bool fullWorldLongExtent = false; + if( fabs(ct->lim.lam * ct->del.lam - 2 * M_PI) < 1e-10 ) + { + fullWorldLongExtent = true; + } + + /* skip tables that don't match our point at all (longitude check). */ + else if( ct->ll.lam > input.lam || ct->ll.lam + (ct->lim.lam-1) * ct->del.lam < input.lam ) continue; @@ -78,8 +88,17 @@ static double read_vgrid_value( PJ *defn, PJ_LP input, int *gridlist_count_p, PJ { struct CTABLE *ct1 = child->ct; - if( ct1->ll.phi > input.phi || ct1->ll.lam > input.lam - || ct1->ll.phi+(ct1->lim.phi-1)*ct1->del.phi < input.phi + fullWorldLongExtent = false; + + if( ct1->ll.phi > input.phi + || ct1->ll.phi+(ct1->lim.phi-1)*ct1->del.phi < input.phi) + continue; + + if( fabs(ct1->lim.lam * ct1->del.lam - 2 * M_PI) < 1e-10 ) + { + fullWorldLongExtent = true; + } + else if( ct1->ll.lam > input.lam || ct1->ll.lam+(ct1->lim.lam-1)*ct1->del.lam < input.lam) continue; @@ -98,24 +117,41 @@ static double read_vgrid_value( PJ *defn, PJ_LP input, int *gridlist_count_p, PJ } /* load the grid shift info if we don't have it. */ - if( ct->cvs == nullptr && !pj_gridinfo_load( pj_get_ctx(defn), gi ) ) + if( ct->cvs == nullptr ) { - pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return PJD_ERR_FAILED_TO_LOAD_GRID; + if( !pj_gridinfo_load( pj_get_ctx(defn), gi ) || ct->cvs == nullptr ) + { + pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return PJD_ERR_FAILED_TO_LOAD_GRID; + } } /* Interpolation a location within the grid */ grid_x = (input.lam - ct->ll.lam) / ct->del.lam; + if( fullWorldLongExtent ) { + // The first fmod goes to ]-lim, lim[ range + // So we add lim again to be in ]0, 2*lim[ and fmod again + grid_x = fmod( + fmod(grid_x + ct->lim.lam, ct->lim.lam) + ct->lim.lam, + ct->lim.lam); + } grid_y = (input.phi - ct->ll.phi) / ct->del.phi; grid_ix = lround(floor(grid_x)); + assert(grid_ix >= 0 && grid_ix < ct->lim.lam); grid_iy = lround(floor(grid_y)); + assert(grid_iy >= 0 && grid_iy < ct->lim.phi); grid_x -= grid_ix; grid_y -= grid_iy; grid_ix2 = grid_ix + 1; - if( grid_ix2 >= ct->lim.lam ) - grid_ix2 = ct->lim.lam - 1; + if( grid_ix2 >= ct->lim.lam ) { + if( fullWorldLongExtent ) { + grid_ix2 = 0; + } else { + grid_ix2 = ct->lim.lam - 1; + } + } grid_iy2 = grid_iy + 1; if( grid_iy2 >= ct->lim.phi ) grid_iy2 = ct->lim.phi - 1; @@ -129,28 +165,28 @@ static double read_vgrid_value( PJ *defn, PJ_LP input, int *gridlist_count_p, PJ double total_weight = 0.0; int n_weights = 0; value = 0.0f; - if( !is_nodata(value_a) ) + if( !is_nodata(value_a, vmultiplier) ) { double weight = (1.0-grid_x) * (1.0-grid_y); value += value_a * weight; total_weight += weight; n_weights ++; } - if( !is_nodata(value_b) ) + if( !is_nodata(value_b, vmultiplier) ) { double weight = (grid_x) * (1.0-grid_y); value += value_b * weight; total_weight += weight; n_weights ++; } - if( !is_nodata(value_c) ) + if( !is_nodata(value_c, vmultiplier) ) { double weight = (1.0-grid_x) * (grid_y); value += value_c * weight; total_weight += weight; n_weights ++; } - if( !is_nodata(value_d) ) + if( !is_nodata(value_d, vmultiplier) ) { double weight = (grid_x) * (grid_y); value += value_d * weight; @@ -165,7 +201,7 @@ static double read_vgrid_value( PJ *defn, PJ_LP input, int *gridlist_count_p, PJ } - return value; + return value * vmultiplier; } /************************************************************************/ @@ -218,7 +254,7 @@ int pj_apply_vgridshift( PJ *defn, const char *listname, input.phi = y[io]; input.lam = x[io]; - value = read_vgrid_value(defn, input, gridlist_count_p, tables, &ct); + value = read_vgrid_value(defn, input, 1.0, gridlist_count_p, tables, &ct); if( inverse ) z[io] -= value; @@ -310,7 +346,7 @@ int proj_vgrid_init(PJ* P, const char *grids) { } /***********************************************/ -double proj_vgrid_value(PJ *P, PJ_LP lp){ +double proj_vgrid_value(PJ *P, PJ_LP lp, double vmultiplier){ /*********************************************** Read grid value at position lp in grids loaded @@ -324,7 +360,7 @@ double proj_vgrid_value(PJ *P, PJ_LP lp){ double value; memset(&used_grid, 0, sizeof(struct CTABLE)); - value = read_vgrid_value(P, lp, &(P->vgridlist_geoid_count), P->vgridlist_geoid, &used_grid); + value = read_vgrid_value(P, lp, vmultiplier, &(P->vgridlist_geoid_count), P->vgridlist_geoid, &used_grid); proj_log_trace(P, "proj_vgrid_value: (%f, %f) = %f", lp.lam*RAD_TO_DEG, lp.phi*RAD_TO_DEG, value); return value; diff --git a/src/apps/cct.cpp b/src/apps/cct.cpp index 34bf0777..d29b58fb 100644 --- a/src/apps/cct.cpp +++ b/src/apps/cct.cpp @@ -81,7 +81,6 @@ Thomas Knudsen, thokn@sdfe.dk, 2016-05-25/2017-10-26 #include "proj.h" #include "proj_internal.h" #include "proj_strtod.h" -#include "proj_internal.h" #include "optargpm.h" @@ -228,6 +227,7 @@ int main(int argc, char **argv) { fout = stdout; + /* coverity[tainted_data] */ o = opt_parse (argc, argv, "hvI", "cdozts", longflags, longkeys); if (nullptr==o) return 0; @@ -368,6 +368,7 @@ int main(int argc, char **argv) { point.lpzt.phi = proj_torad (point.lpzt.phi); } err = proj_errno_reset (P); + /* coverity[returned_value] */ point = proj_trans (P, direction, point); if (HUGE_VAL==point.xyzt.x) { diff --git a/src/apps/cs2cs.cpp b/src/apps/cs2cs.cpp index 150548c5..20e5e73c 100644 --- a/src/apps/cs2cs.cpp +++ b/src/apps/cs2cs.cpp @@ -45,6 +45,7 @@ #include "proj.h" #include "proj_internal.h" #include "emess.h" +#include "utils.h" // clang-format on #define MAX_LINE 1000 @@ -68,8 +69,8 @@ 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] ] [ +opts[=arg] ]\n" - " [+to [+opts[=arg] [ files ]\n"; + "%s\nusage: %s [-dDeEfIlrstvwW [args]] [+opt[=arg] ...]\n" + " [+to +opt[=arg] ...] [file ...]\n"; static double (*informat)(const char *, char **); /* input data deformatter function */ @@ -113,6 +114,19 @@ static void process(FILE *fid) z = strtod(s, &s); + /* To avoid breaking existing tests, we read what is a possible t */ + /* component of the input and rewind the s-pointer so that the final */ + /* output has consistant behaviour, with or without t values. */ + /* This is a bit of a hack, in most cases 4D coordinates will be */ + /* written to STDOUT (except when using -E) but the output format */ + /* speficied with -f is not respected for the t component, rather it */ + /* is forward verbatim from the input. */ + char *before_time = s; + double t = strtod(s, &s); + if( s == before_time ) + t = HUGE_VAL; + s = before_time; + if (data.v == HUGE_VAL) data.u = HUGE_VAL; @@ -120,11 +134,11 @@ static void process(FILE *fid) --s; /* assumed we gobbled \n */ if (echoin) { - char t; - t = *s; + char temp; + temp = *s; *s = '\0'; (void)fputs(line, stdout); - *s = t; + *s = temp; putchar('\t'); } @@ -141,7 +155,7 @@ static void process(FILE *fid) coord.xyzt.x = data.u; coord.xyzt.y = data.v; coord.xyzt.z = z; - coord.xyzt.t = HUGE_VAL; + coord.xyzt.t = t; coord = proj_trans(transformation, PJ_FWD, coord); data.u = coord.xyz.x; data.v = coord.xyz.y; @@ -206,10 +220,10 @@ static void process(FILE *fid) } /************************************************************************/ -/* instanciate_crs() */ +/* instantiate_crs() */ /************************************************************************/ -static PJ *instanciate_crs(const std::string &definition, +static PJ *instantiate_crs(const std::string &definition, bool &isGeog, double &toRadians, bool &isLatFirst) { PJ *crs = proj_create(nullptr, @@ -263,13 +277,6 @@ static std::string get_geog_crs_proj_string_from_proj_crs(PJ *src, double &toRadians, bool &isLatFirst) { auto srcType = proj_get_type(src); - if (srcType == PJ_TYPE_BOUND_CRS) { - auto base = proj_get_source_crs(nullptr, src); - assert(base); - proj_destroy(src); - src = base; - srcType = proj_get_type(src); - } if (srcType != PJ_TYPE_PROJECTED_CRS) { return std::string(); } @@ -518,6 +525,13 @@ int main(int argc, char **argv) { if (eargc == 0) /* if no specific files force sysin */ eargv[eargc++] = const_cast<char *>("-"); + if( oform ) { + if( !validate_form_string_for_numbers(oform) ) { + emess(3, "invalid format string"); + exit(0); + } + } + /* * If the user has requested inverse, then just reverse the * coordinate systems. @@ -541,7 +555,7 @@ int main(int argc, char **argv) { PJ *src = nullptr; if (!fromStr.empty()) { bool ignored; - src = instanciate_crs(fromStr, srcIsGeog, + src = instantiate_crs(fromStr, srcIsGeog, srcToRadians, ignored); if (!src) { emess(3, "cannot instantiate source coordinate system"); @@ -550,7 +564,7 @@ int main(int argc, char **argv) { PJ *dst = nullptr; if (!toStr.empty()) { - dst = instanciate_crs(toStr, destIsGeog, + dst = instantiate_crs(toStr, destIsGeog, destToRadians, destIsLatLong); if (!dst) { emess(3, "cannot instantiate target coordinate system"); diff --git a/src/apps/emess.cpp b/src/apps/emess.cpp index 144e9e23..53018ba8 100644 --- a/src/apps/emess.cpp +++ b/src/apps/emess.cpp @@ -20,6 +20,7 @@ #include <string.h> #include "proj_api.h" +#include "proj_config.h" #define EMESS_ROUTINE #include "emess.h" @@ -29,7 +30,7 @@ emess(int code, const char *fmt, ...) { va_start(args, fmt); /* prefix program name, if given */ - if (fmt != nullptr) + if (emess_dat.Prog_name != nullptr) (void)fprintf(stderr,"%s\n<%s>: ",pj_get_release(), emess_dat.Prog_name); /* print file name and line, if given */ diff --git a/src/apps/geod.cpp b/src/apps/geod.cpp index 7225856e..b46188d3 100644 --- a/src/apps/geod.cpp +++ b/src/apps/geod.cpp @@ -22,7 +22,7 @@ static const char *osform = "%.3f"; /* output format for S */ static char pline[50]; /* work string */ static const char *usage = -"%s\nusage: %s [ -afFIlptwW [args] ] [ +opts[=arg] ] [ files ]\n"; +"%s\nusage: %s [-afFIlptwW [args]] [+opt[=arg] ...] [file ...]\n"; static void printLL(double p, double l) { diff --git a/src/apps/gie.cpp b/src/apps/gie.cpp index abed11c0..2f401984 100644 --- a/src/apps/gie.cpp +++ b/src/apps/gie.cpp @@ -117,7 +117,6 @@ Thomas Knudsen, thokn@sdfe.dk, 2017-10-01/2017-10-08 #include "proj_internal.h" #include "proj_math.h" #include "proj_strtod.h" -#include "proj_internal.h" #include "optargpm.h" @@ -148,7 +147,7 @@ static ffio *ffio_destroy (ffio *G); static ffio *ffio_create (const char **tags, size_t n_tags, size_t max_record_size); static const char *gie_tags[] = { - "<gie>", "operation", "use_proj4_init_rules", + "<gie>", "operation", "crs_src", "crs_dst", "use_proj4_init_rules", "accept", "expect", "roundtrip", "banner", "verbose", "direction", "tolerance", "ignore", "require_grid", "echo", "skip", "</gie>" }; @@ -175,6 +174,8 @@ static const char *err_const_from_errno (int err); typedef struct { char operation[MAX_OPERATION+1]; + char crs_dst[MAX_OPERATION+1]; + char crs_src[MAX_OPERATION+1]; PJ *P; PJ_COORD a, b, c, e; PJ_DIRECTION dir; @@ -247,6 +248,7 @@ int main (int argc, char **argv) { T.ignore = 5555; /* Error code that will not be issued by proj_create() */ T.use_proj4_init_rules = FALSE; + /* coverity[tainted_data] */ o = opt_parse (argc, argv, "hlvq", "o", longflags, longkeys); if (nullptr==o) return 0; @@ -300,6 +302,20 @@ int main (int argc, char **argv) { return 1; } + for (i = 0; i < o->fargc; i++ ) { + FILE* f = fopen (o->fargv[i], "rt"); + if (f == nullptr) { + fprintf ( + T.fout, + "%sCannot open specified input file '%s' - bye!\n", + delim, + o->fargv[i] + ); + return 1; + } + fclose(f); + } + for (i = 0; i < o->fargc; i++) process_file (o->fargv[i]); @@ -370,8 +386,6 @@ static int another_failing_roundtrip (void) { } static int process_file (const char *fname) { - FILE *f; - F->lineno = F->next_lineno = F->level = 0; T.op_ok = T.total_ok = 0; T.op_ko = T.total_ko = 0; @@ -383,15 +397,8 @@ static int process_file (const char *fname) { return 0; } - f = fopen (fname, "rt"); - if (nullptr==f) { - if (T.verbosity > 0) { - fprintf (T.fout, "%sCannot open spec'd input file '%s' - bye!\n", delim, fname); - return 2; - } - errmsg (2, "Cannot open spec'd input file '%s' - bye!\n", fname); - } - F->f = f; + /* We have already tested in main that the file exists */ + F->f = fopen (fname, "rt"); if (T.verbosity > 0) fprintf (T.fout, "%sReading file '%s'\n", delim, fname); @@ -405,7 +412,7 @@ static int process_file (const char *fname) { } } - fclose (f); + fclose (F->f); F->lineno = F->next_lineno = 0; T.grand_ok += T.total_ok; @@ -602,6 +609,65 @@ either a conversion or a transformation) return 0; } +static int crs_to_crs_operation() { + T.op_id++; + T.operation_lineno = F->lineno; + + if (T.verbosity > 1) { + char buffer[80]; + finish_previous_operation (F->args); + snprintf(buffer, 80, "%-36.36s -> %-36.36s", T.crs_src, T.crs_dst); + banner (buffer); + } + + T.op_ok = 0; + T.op_ko = 0; + T.op_skip = 0; + T.skip_test = 0; + + direction ("forward"); + tolerance ("0.5 mm"); + ignore ("pjd_err_dont_skip"); + + proj_errno_reset (T.P); + + if (T.P) + proj_destroy (T.P); + proj_errno_reset (nullptr); + proj_context_use_proj4_init_rules(nullptr, T.use_proj4_init_rules); + + + T.P = proj_create_crs_to_crs(nullptr, T.crs_src, T.crs_dst, nullptr); + + strcpy(T.crs_src, ""); + strcpy(T.crs_dst, ""); + return 0; +} + +static int crs_src(const char *args) { + strncpy (&(T.crs_src[0]), F->args, MAX_OPERATION); + T.crs_src[MAX_OPERATION] = '\0'; + (void) args; + + if (strcmp(T.crs_src, "") != 0 && strcmp(T.crs_dst, "") != 0) { + crs_to_crs_operation(); + } + + return 0; +} + +static int crs_dst(const char *args) { + strncpy (&(T.crs_dst[0]), F->args, MAX_OPERATION); + T.crs_dst[MAX_OPERATION] = '\0'; + (void) args; + + if (strcmp(T.crs_src, "") != 0 && strcmp(T.crs_dst, "") != 0) { + crs_to_crs_operation(); + } + + return 0; +} + static PJ_COORD torad_coord (PJ *P, PJ_DIRECTION dir, PJ_COORD a) { size_t i, n; const char *axis = "enut"; @@ -939,7 +1005,8 @@ Tell GIE what to expect, when transforming the ACCEPTed input else d = proj_xyz_dist (co, ce); - if (d > T.tolerance) + // Test written like that to handle NaN + if (!(d <= T.tolerance)) return expect_message (d, args); succs++; @@ -995,6 +1062,8 @@ static int dispatch (const char *cmnd, const char *args) { if (T.skip) return SKIP; if (0==strcmp (cmnd, "operation")) return operation ((char *) args); + if (0==strcmp (cmnd, "crs_src")) return crs_src (args); + if (0==strcmp (cmnd, "crs_dst")) return crs_dst (args); if (T.skip_test) { if (0==strcmp (cmnd, "expect")) return another_skip(); @@ -1028,7 +1097,7 @@ static const struct errno_vs_err_const lookup[] = { {"pjd_err_no_colon_in_init_string" , -3}, {"pjd_err_proj_not_named" , -4}, {"pjd_err_unknown_projection_id" , -5}, - {"pjd_err_eccentricity_is_one" , -6}, + {"pjd_err_invalid_eccentricity" , -6}, {"pjd_err_unknown_unit_id" , -7}, {"pjd_err_invalid_boolean_param" , -8}, {"pjd_err_unknown_ellp_param" , -9}, @@ -1052,7 +1121,7 @@ static const struct errno_vs_err_const lookup[] = { {"pjd_err_w_or_m_zero_or_less" , -27}, {"pjd_err_lsat_not_in_range" , -28}, {"pjd_err_path_not_in_range" , -29}, - {"pjd_err_h_less_than_zero" , -30}, + {"pjd_err_invalid_h" , -30}, {"pjd_err_k_less_than_zero" , -31}, {"pjd_err_lat_1_or_2_zero_or_90" , -32}, {"pjd_err_lat_0_or_alpha_eq_90" , -33}, @@ -1083,6 +1152,7 @@ static const struct errno_vs_err_const lookup[] = { {"pjd_err_invalid_arg" , -58}, {"pjd_err_inconsistent_unit" , -59}, {"pjd_err_mutually_exclusive_args" , -60}, + {"pjd_err_generic_error" , -61}, {"pjd_err_dont_skip" , 5555}, {"pjd_err_unknown" , 9999}, {"pjd_err_enomem" , ENOMEM}, diff --git a/src/apps/optargpm.h b/src/apps/optargpm.h index 035c6f92..f293ad98 100644 --- a/src/apps/optargpm.h +++ b/src/apps/optargpm.h @@ -526,6 +526,7 @@ OPTARGS *opt_parse (int argc, char **argv, const char *flags, const char *keys, c = opt_ordinal (o, crepr); if (0==c) { fprintf (stderr, "Invalid option \"%s\"\n", crepr); + free (o); return nullptr; } @@ -534,6 +535,7 @@ OPTARGS *opt_parse (int argc, char **argv, const char *flags, const char *keys, *equals = '='; if (opt_is_flag (o, c)) { fprintf (stderr, "Option \"%s\" takes no arguments\n", crepr); + free (o); return nullptr; } o->optarg[c] = equals + 1; @@ -544,6 +546,7 @@ OPTARGS *opt_parse (int argc, char **argv, const char *flags, const char *keys, if (!opt_is_flag (o, c)) { if ((argc==i + 1) || ('+'==argv[i+1][0]) || ('-'==argv[i+1][0])) { fprintf (stderr, "Missing argument for option \"%s\"\n", crepr); + free (o); return nullptr; } o->optarg[c] = argv[i + 1]; @@ -553,6 +556,7 @@ OPTARGS *opt_parse (int argc, char **argv, const char *flags, const char *keys, if (!opt_is_flag (o, c)) { fprintf (stderr, "Expected flag style long option here, but got \"%s\"\n", crepr); + free (o); return nullptr; } @@ -564,6 +568,7 @@ OPTARGS *opt_parse (int argc, char **argv, const char *flags, const char *keys, /* classic short options */ if (nullptr==o->optarg[c]) { fprintf (stderr, "Invalid option \"%s\"\n", crepr); + free (o); return nullptr; } @@ -580,6 +585,7 @@ OPTARGS *opt_parse (int argc, char **argv, const char *flags, const char *keys, if ((argc==i + 1) || ('+'==argv[i+1][0]) || ('-'==argv[i+1][0])) { fprintf (stderr, "Bad or missing arg for option \"%s\"\n", crepr); + free (o); return nullptr; } o->optarg[(int) c] = argv[i + 1]; diff --git a/src/apps/proj.cpp b/src/apps/proj.cpp index 298a44e8..888d723f 100644 --- a/src/apps/proj.cpp +++ b/src/apps/proj.cpp @@ -7,6 +7,7 @@ #include <string.h> #include <math.h> #include "emess.h" +#include "utils.h" #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__WIN32__) # include <fcntl.h> @@ -22,7 +23,6 @@ static PJ *Proj; static union { - PJ_UV (*generic)(PJ_UV, PJ *); PJ_XY (*fwd)(PJ_LP, PJ *); PJ_LP (*inv)(PJ_XY, PJ *); } proj; @@ -46,7 +46,7 @@ static char oform_buffer[16]; /* Buffer for oform when using -d */ static const char *oterr = "*\t*", /* output line for unprojectable input */ - *usage = "%s\nusage: %s [ -bdeEfiIlmorsStTvVwW [args] ] [ +opts[=arg] ] [ files ]\n"; + *usage = "%s\nusage: %s [-bdeEfiIlmorsStTvVwW [args]] [+opt[=arg] ...] [file ...]\n"; static PJ_FACTORS facs; @@ -462,6 +462,13 @@ int main(int argc, char **argv) { if (eargc == 0) /* if no specific files force sysin */ eargv[eargc++] = const_cast<char*>("-"); + if( oform ) { + if( !validate_form_string_for_numbers(oform) ) { + emess(3, "invalid format string"); + exit(0); + } + } + /* done with parameter and control input */ if (inverse && postscale) { prescale = 1; @@ -488,7 +495,6 @@ int main(int argc, char **argv) { proj.inv = pj_inv; } else proj.fwd = pj_fwd; - /* set input formatting control */ if (mon) { pj_pr_list(Proj); @@ -533,7 +539,7 @@ int main(int argc, char **argv) { } else { if ((fid = fopen(*eargv, "rb")) == nullptr) { - emess(-2, *eargv, "input file"); + emess(-2, "input file: %s", *eargv); continue; } emess_dat.File_name = *eargv; diff --git a/src/apps/proj_strtod.cpp b/src/apps/proj_strtod.cpp index b8edc6a3..d4674705 100644 --- a/src/apps/proj_strtod.cpp +++ b/src/apps/proj_strtod.cpp @@ -309,7 +309,7 @@ double proj_strtod(const char *str, char **endptr) { number = exponent < 0? number / ex: number * ex; } else - number *= pow (10, exponent); + number *= pow (10.0, static_cast<double>(exponent)); return number; } diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index 9f908c8a..9d724522 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -77,7 +77,8 @@ struct OutputOptions { static void usage() { std::cerr - << "usage: projinfo [-o formats] [-k crs|operation] [--summary] [-q]" + << "usage: projinfo [-o formats] [-k crs|operation|ellipsoid] " + "[--summary] [-q]" << std::endl << " ([--area name_or_code] | " "[--bbox west_long,south_lat,east_long,north_lat]) " @@ -136,11 +137,12 @@ static std::string c_ify_string(const std::string &str) { // --------------------------------------------------------------------------- -static BaseObjectNNPtr buildObject(DatabaseContextPtr dbContext, - const std::string &user_string, - bool kindIsCRS, const std::string &context, - bool buildBoundCRSToWGS84, CoordinateOperationContext::IntermediateCRSUse allowUseIntermediateCRS, - bool quiet) { +static BaseObjectNNPtr buildObject( + DatabaseContextPtr dbContext, const std::string &user_string, + const std::string &kind, const std::string &context, + bool buildBoundCRSToWGS84, + CoordinateOperationContext::IntermediateCRSUse allowUseIntermediateCRS, + bool quiet) { BaseObjectPtr obj; std::string l_user_string(user_string); @@ -174,10 +176,13 @@ static BaseObjectNNPtr buildObject(DatabaseContextPtr dbContext, try { auto tokens = split(l_user_string, ':'); - if (!kindIsCRS && tokens.size() == 2) { + if (kind == "operation" && tokens.size() == 2) { 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 { // Convenience to be able to use C escaped strings... if (l_user_string.size() > 2 && l_user_string[0] == '"' && @@ -213,7 +218,8 @@ static BaseObjectNNPtr buildObject(DatabaseContextPtr dbContext, if (buildBoundCRSToWGS84) { auto crs = std::dynamic_pointer_cast<CRS>(obj); if (crs) { - obj = crs->createBoundCRSToWGS84IfPossible(dbContext, allowUseIntermediateCRS) + obj = crs->createBoundCRSToWGS84IfPossible(dbContext, + allowUseIntermediateCRS) .as_nullable(); } } @@ -223,8 +229,10 @@ static BaseObjectNNPtr buildObject(DatabaseContextPtr dbContext, // --------------------------------------------------------------------------- -static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, - CoordinateOperationContext::IntermediateCRSUse allowUseIntermediateCRS, const OutputOptions &outputOpt) { +static void outputObject( + DatabaseContextPtr dbContext, BaseObjectNNPtr obj, + CoordinateOperationContext::IntermediateCRSUse allowUseIntermediateCRS, + const OutputOptions &outputOpt) { auto identified = dynamic_cast<const IdentifiedObject *>(obj.get()); if (!outputOpt.quiet && identified && identified->isDeprecated()) { @@ -260,7 +268,7 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, } auto crs = nn_dynamic_pointer_cast<CRS>(obj); if (!outputOpt.quiet) { - if( crs ) { + if (crs) { std::cout << "PROJ.4 string:" << std::endl; } else { std::cout << "PROJ string:" << std::endl; @@ -271,8 +279,8 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, if (crs) { objToExport = nn_dynamic_pointer_cast<IPROJStringExportable>( - crs->createBoundCRSToWGS84IfPossible(dbContext, - allowUseIntermediateCRS)); + crs->createBoundCRSToWGS84IfPossible( + dbContext, allowUseIntermediateCRS)); } if (!objToExport) { objToExport = projStringExportable; @@ -411,8 +419,8 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, std::shared_ptr<IWKTExportable> objToExport; if (crs) { objToExport = nn_dynamic_pointer_cast<IWKTExportable>( - crs->createBoundCRSToWGS84IfPossible(dbContext, - allowUseIntermediateCRS)); + crs->createBoundCRSToWGS84IfPossible( + dbContext, allowUseIntermediateCRS)); } if (!objToExport) { objToExport = wktExportable; @@ -461,11 +469,42 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj, } } } + + auto op = dynamic_cast<CoordinateOperation *>(obj.get()); + if (op && dbContext && getenv("PROJINFO_NO_GRID_CHECK") == nullptr) { + try { + auto setGrids = op->gridsNeeded(dbContext); + bool firstWarning = true; + for (const auto &grid : setGrids) { + if (!grid.available) { + if (firstWarning) { + std::cout << std::endl; + firstWarning = false; + } + std::cout << "Grid " << grid.shortName + << " needed but not found on the system."; + if (!grid.packageName.empty()) { + std::cout << " Can be obtained from the " + << grid.packageName << " package"; + if (!grid.url.empty()) { + std::cout << " at " << grid.url; + } + } else if (!grid.url.empty()) { + std::cout << " Can be obtained at " << grid.url; + } + std::cout << std::endl; + } + } + } catch (const std::exception &e) { + std::cerr << "Error in gridsNeeded(): " << e.what() << std::endl; + } + } } // --------------------------------------------------------------------------- -static void outputOperationSummary(const CoordinateOperationNNPtr &op) { +static void outputOperationSummary(const CoordinateOperationNNPtr &op, + const DatabaseContextPtr &dbContext) { auto ids = op->identifiers(); if (!ids.empty()) { std::cout << *(ids[0]->codeSpace()) << ":" << ids[0]->code(); @@ -505,6 +544,22 @@ static void outputOperationSummary(const CoordinateOperationNNPtr &op) { std::cout << "unknown domain of validity"; } + if (op->hasBallparkTransformation()) { + std::cout << ", has ballpark transformation"; + } + + if (dbContext && getenv("PROJINFO_NO_GRID_CHECK") == nullptr) { + try { + auto setGrids = op->gridsNeeded(dbContext); + for (const auto &grid : setGrids) { + if (!grid.available) { + std::cout << ", at least one grid missing"; + break; + } + } + } catch (const std::exception &) { + } + } std::cout << std::endl; } @@ -514,26 +569,25 @@ static void outputOperations( DatabaseContextPtr dbContext, const std::string &sourceCRSStr, const std::string &targetCRSStr, const ExtentPtr &bboxFilter, CoordinateOperationContext::SpatialCriterion spatialCriterion, + bool spatialCriterionExplicitlySpecified, CoordinateOperationContext::SourceTargetCRSExtentUse crsExtentUse, CoordinateOperationContext::GridAvailabilityUse gridAvailabilityUse, CoordinateOperationContext::IntermediateCRSUse allowUseIntermediateCRS, const std::vector<std::pair<std::string, std::string>> &pivots, const std::string &authority, bool usePROJGridAlternatives, bool showSuperseded, const OutputOptions &outputOpt, bool summary) { - auto sourceObj = buildObject(dbContext, sourceCRSStr, true, "source CRS", - false, - CoordinateOperationContext::IntermediateCRSUse::NEVER, - outputOpt.quiet); + auto sourceObj = buildObject( + dbContext, sourceCRSStr, "crs", "source CRS", false, + CoordinateOperationContext::IntermediateCRSUse::NEVER, outputOpt.quiet); auto sourceCRS = nn_dynamic_pointer_cast<CRS>(sourceObj); if (!sourceCRS) { std::cerr << "source CRS string is not a CRS" << std::endl; std::exit(1); } - auto targetObj = buildObject(dbContext, targetCRSStr, true, "target CRS", - false, - CoordinateOperationContext::IntermediateCRSUse::NEVER, - outputOpt.quiet); + auto targetObj = buildObject( + dbContext, targetCRSStr, "crs", "target CRS", false, + CoordinateOperationContext::IntermediateCRSUse::NEVER, outputOpt.quiet); auto targetCRS = nn_dynamic_pointer_cast<CRS>(targetObj); if (!targetCRS) { std::cerr << "target CRS string is not a CRS" << std::endl; @@ -541,6 +595,7 @@ static void outputOperations( } std::vector<CoordinateOperationNNPtr> list; + size_t spatialCriterionPartialIntersectionResultCount = 0; try { auto authFactory = dbContext @@ -558,6 +613,21 @@ static void outputOperations( ctxt->setDiscardSuperseded(!showSuperseded); list = CoordinateOperationFactory::create()->createOperations( NN_NO_CHECK(sourceCRS), NN_NO_CHECK(targetCRS), ctxt); + if (!spatialCriterionExplicitlySpecified && + spatialCriterion == CoordinateOperationContext::SpatialCriterion:: + STRICT_CONTAINMENT) { + try { + ctxt->setSpatialCriterion( + CoordinateOperationContext::SpatialCriterion:: + PARTIAL_INTERSECTION); + spatialCriterionPartialIntersectionResultCount = + CoordinateOperationFactory::create() + ->createOperations(NN_NO_CHECK(sourceCRS), + NN_NO_CHECK(targetCRS), ctxt) + .size(); + } catch (const std::exception &) { + } + } } catch (const std::exception &e) { std::cerr << "createOperations() failed with: " << e.what() << std::endl; @@ -567,28 +637,31 @@ static void outputOperations( outputObject(dbContext, list[0], allowUseIntermediateCRS, outputOpt); return; } + std::cout << "Candidate operations found: " << list.size() << std::endl; + if (spatialCriterionPartialIntersectionResultCount > list.size()) { + std::cout << "Note: using '--spatial-test intersects' would bring " + "more results (" + << spatialCriterionPartialIntersectionResultCount << ")" + << std::endl; + } if (summary) { - std::cout << "Candidate operations found: " << list.size() << std::endl; for (const auto &op : list) { - outputOperationSummary(op); + outputOperationSummary(op, dbContext); } } else { bool first = true; for (size_t i = 0; i < list.size(); ++i) { const auto &op = list[i]; - if (list.size() > 1) { - if (!first) { - std::cout << std::endl; - } - first = false; - std::cout << "-------------------------------------" - << std::endl; - std::cout << "Operation n" - "\xC2\xB0" - << (i + 1) << ":" << std::endl - << std::endl; + if (!first) { + std::cout << std::endl; } - outputOperationSummary(op); + first = false; + std::cout << "-------------------------------------" << std::endl; + std::cout << "Operation n" + "\xC2\xB0" + << (i + 1) << ":" << std::endl + << std::endl; + outputOperationSummary(op, dbContext); std::cout << std::endl; outputObject(dbContext, op, allowUseIntermediateCRS, outputOpt); } @@ -610,10 +683,11 @@ int main(int argc, char **argv) { std::string targetCRSStr; bool outputSwithSpecified = false; OutputOptions outputOpt; - bool kindIsCRS = true; + std::string objectKind; bool summary = false; ExtentPtr bboxFilter = nullptr; std::string area; + bool spatialCriterionExplicitlySpecified = false; CoordinateOperationContext::SpatialCriterion spatialCriterion = CoordinateOperationContext::SpatialCriterion::STRICT_CONTAINMENT; CoordinateOperationContext::SourceTargetCRSExtentUse crsExtentUse = @@ -622,7 +696,8 @@ int main(int argc, char **argv) { CoordinateOperationContext::GridAvailabilityUse gridAvailabilityUse = CoordinateOperationContext::GridAvailabilityUse::USE_FOR_SORTING; CoordinateOperationContext::IntermediateCRSUse allowUseIntermediateCRS = - CoordinateOperationContext::IntermediateCRSUse::IF_NO_DIRECT_TRANSFORMATION; + CoordinateOperationContext::IntermediateCRSUse:: + IF_NO_DIRECT_TRANSFORMATION; std::vector<std::pair<std::string, std::string>> pivots; bool usePROJGridAlternatives = true; std::string mainDBPath; @@ -736,9 +811,11 @@ int main(int argc, char **argv) { i++; std::string kind(argv[i]); if (ci_equal(kind, "crs") || ci_equal(kind, "srs")) { - kindIsCRS = true; + objectKind = "crs"; } else if (ci_equal(kind, "operation")) { - kindIsCRS = false; + objectKind = "operation"; + } else if (ci_equal(kind, "ellipsoid")) { + objectKind = "ellipsoid"; } else { std::cerr << "Unrecognized value for option -k: " << kind << std::endl; @@ -768,6 +845,7 @@ int main(int argc, char **argv) { } else if (arg == "--spatial-test" && i + 1 < argc) { i++; std::string value(argv[i]); + spatialCriterionExplicitlySpecified = true; if (ci_equal(value, "contains")) { spatialCriterion = CoordinateOperationContext:: SpatialCriterion::STRICT_CONTAINMENT; @@ -822,9 +900,10 @@ int main(int argc, char **argv) { if (ci_equal(std::string(value), "always")) { allowUseIntermediateCRS = CoordinateOperationContext::IntermediateCRSUse::ALWAYS; - } else if (ci_equal(std::string(value), "if_no_direct_transformation")) { - allowUseIntermediateCRS = - CoordinateOperationContext::IntermediateCRSUse::IF_NO_DIRECT_TRANSFORMATION; + } else if (ci_equal(std::string(value), + "if_no_direct_transformation")) { + allowUseIntermediateCRS = CoordinateOperationContext:: + IntermediateCRSUse::IF_NO_DIRECT_TRANSFORMATION; } else if (ci_equal(std::string(value), "never")) { allowUseIntermediateCRS = CoordinateOperationContext::IntermediateCRSUse::NEVER; @@ -918,77 +997,86 @@ int main(int argc, char **argv) { } if (outputOpt.quiet && - (outputOpt.PROJ5 + outputOpt.WKT2_2018 + - outputOpt.WKT2_2015 + outputOpt.WKT1_GDAL) != 1) { + (outputOpt.PROJ5 + outputOpt.WKT2_2018 + outputOpt.WKT2_2015 + + outputOpt.WKT1_GDAL) != 1) { std::cerr << "-q can only be used with a single output format" << std::endl; usage(); } if (!user_string.empty()) { - auto obj(buildObject(dbContext, user_string, kindIsCRS, "input string", - buildBoundCRSToWGS84, allowUseIntermediateCRS, - outputOpt.quiet)); - if (guessDialect) { - auto dialect = WKTParser().guessDialect(user_string); - std::cout << "Guessed WKT dialect: "; - if (dialect == WKTParser::WKTGuessedDialect::WKT2_2018) { - std::cout << "WKT2_2018"; - } else if (dialect == WKTParser::WKTGuessedDialect::WKT2_2015) { - std::cout << "WKT2_2015"; - } else if (dialect == WKTParser::WKTGuessedDialect::WKT1_GDAL) { - std::cout << "WKT1_GDAL"; - } else if (dialect == WKTParser::WKTGuessedDialect::WKT1_ESRI) { - std::cout << "WKT1_ESRI"; - } else { - std::cout << "Not WKT / unknown"; + try { + auto obj(buildObject(dbContext, user_string, objectKind, + "input string", buildBoundCRSToWGS84, + allowUseIntermediateCRS, outputOpt.quiet)); + if (guessDialect) { + auto dialect = WKTParser().guessDialect(user_string); + std::cout << "Guessed WKT dialect: "; + if (dialect == WKTParser::WKTGuessedDialect::WKT2_2018) { + std::cout << "WKT2_2018"; + } else if (dialect == WKTParser::WKTGuessedDialect::WKT2_2015) { + std::cout << "WKT2_2015"; + } else if (dialect == WKTParser::WKTGuessedDialect::WKT1_GDAL) { + std::cout << "WKT1_GDAL"; + } else if (dialect == WKTParser::WKTGuessedDialect::WKT1_ESRI) { + std::cout << "WKT1_ESRI"; + } else { + std::cout << "Not WKT / unknown"; + } + std::cout << std::endl; } - std::cout << std::endl; - } - outputObject(dbContext, obj, allowUseIntermediateCRS, outputOpt); - if (identify) { - auto crs = dynamic_cast<CRS *>(obj.get()); - if (crs) { - try { - auto res = crs->identify( - dbContext - ? AuthorityFactory::create(NN_NO_CHECK(dbContext), - authority) - .as_nullable() - : nullptr); - std::cout << std::endl; - std::cout << "Identification match count: " << res.size() - << std::endl; - for (const auto &pair : res) { - const auto &identifiedCRS = pair.first; - const auto &ids = identifiedCRS->identifiers(); - if (!ids.empty()) { - std::cout << *ids[0]->codeSpace() << ":" - << ids[0]->code() << ": " << pair.second - << " %" << std::endl; - } else { - auto boundCRS = - dynamic_cast<BoundCRS *>(identifiedCRS.get()); - if (boundCRS && - !boundCRS->baseCRS()->identifiers().empty()) { - const auto &idsBase = - boundCRS->baseCRS()->identifiers(); - std::cout << "BoundCRS of " - << *idsBase[0]->codeSpace() << ":" - << idsBase[0]->code() << ": " + outputObject(dbContext, obj, allowUseIntermediateCRS, outputOpt); + if (identify) { + auto crs = dynamic_cast<CRS *>(obj.get()); + if (crs) { + try { + auto res = crs->identify( + dbContext + ? AuthorityFactory::create( + NN_NO_CHECK(dbContext), authority) + .as_nullable() + : nullptr); + std::cout << std::endl; + std::cout + << "Identification match count: " << res.size() + << std::endl; + for (const auto &pair : res) { + const auto &identifiedCRS = pair.first; + const auto &ids = identifiedCRS->identifiers(); + if (!ids.empty()) { + std::cout << *ids[0]->codeSpace() << ":" + << ids[0]->code() << ": " << pair.second << " %" << std::endl; } else { - std::cout - << "un-identifier CRS: " << pair.second - << " %" << std::endl; + auto boundCRS = dynamic_cast<BoundCRS *>( + identifiedCRS.get()); + if (boundCRS && + !boundCRS->baseCRS() + ->identifiers() + .empty()) { + const auto &idsBase = + boundCRS->baseCRS()->identifiers(); + std::cout << "BoundCRS of " + << *idsBase[0]->codeSpace() << ":" + << idsBase[0]->code() << ": " + << pair.second << " %" + << std::endl; + } else { + std::cout + << "un-identifier CRS: " << pair.second + << " %" << std::endl; + } } } + } catch (const std::exception &e) { + std::cerr << "Identification failed: " << e.what() + << std::endl; } - } catch (const std::exception &e) { - std::cerr << "Identification failed: " << e.what() - << std::endl; } } + } catch (const std::exception &e) { + std::cerr << "buildObject failed: " << e.what() << std::endl; + std::exit(1); } } else { @@ -1053,10 +1141,18 @@ int main(int argc, char **argv) { } } - outputOperations( - dbContext, sourceCRSStr, targetCRSStr, bboxFilter, spatialCriterion, - crsExtentUse, gridAvailabilityUse, allowUseIntermediateCRS, pivots, authority, - usePROJGridAlternatives, showSuperseded, outputOpt, summary); + try { + outputOperations(dbContext, sourceCRSStr, targetCRSStr, bboxFilter, + spatialCriterion, + spatialCriterionExplicitlySpecified, crsExtentUse, + gridAvailabilityUse, allowUseIntermediateCRS, + pivots, authority, usePROJGridAlternatives, + showSuperseded, outputOpt, summary); + } catch (const std::exception &e) { + std::cerr << "outputOperations() failed with: " << e.what() + << std::endl; + std::exit(1); + } } return 0; diff --git a/src/apps/utils.cpp b/src/apps/utils.cpp new file mode 100644 index 00000000..7dc809c9 --- /dev/null +++ b/src/apps/utils.cpp @@ -0,0 +1,58 @@ +/****************************************************************************** + * + * Project: PROJ + * Purpose: Utilities for command line arguments + * Author: Even Rouault <even dot rouault at spatialys dot com> + * + ****************************************************************************** + * Copyright (c) 2019, 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. + ****************************************************************************/ + +#include "utils.h" + +#include <string.h> + +bool validate_form_string_for_numbers(const char* formatString) { + /* Only accepts '%[+]?[number]?[.]?[number]?[e|E|f|F|g|G]' */ + bool valid = true; + if( formatString[0] != '%' ) + valid = false; + else { + auto oformLen = strlen(formatString); + for( int i = 1; i < static_cast<int>(oformLen) - 1; i++ ) { + if( !(formatString[i] == '.' || + formatString[i] == '+' || + (formatString[i] >= '0' && formatString[i] <= '9')) ) { + valid = false; + break; + } + } + if( valid ) { + valid = formatString[oformLen-1] == 'e' || + formatString[oformLen-1] == 'E' || + formatString[oformLen-1] == 'f' || + formatString[oformLen-1] == 'F' || + formatString[oformLen-1] == 'g' || + formatString[oformLen-1] == 'G'; + } + } + return valid; +} diff --git a/src/apps/utils.h b/src/apps/utils.h new file mode 100644 index 00000000..99c14091 --- /dev/null +++ b/src/apps/utils.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * + * Project: PROJ + * Purpose: Utilities for command line arguments + * Author: Even Rouault <even dot rouault at spatialys dot com> + * + ****************************************************************************** + * Copyright (c) 2019, 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. + ****************************************************************************/ + +bool validate_form_string_for_numbers(const char* formatString); diff --git a/src/bin_cct.cmake b/src/bin_cct.cmake index e400caf3..d2d61cf5 100644 --- a/src/bin_cct.cmake +++ b/src/bin_cct.cmake @@ -1,13 +1,19 @@ -set(CCT_SRC apps/cct.cpp apps/proj_strtod.cpp apps/proj_strtod.h) +set(CCT_SRC + apps/cct.cpp + apps/proj_strtod.cpp + apps/proj_strtod.h +) set(CCT_INCLUDE apps/optargpm.h) source_group("Source Files\\Bin" FILES ${CCT_SRC}) add_executable(cct ${CCT_SRC} ${CCT_INCLUDE}) target_link_libraries(cct ${PROJ_LIBRARIES}) +target_compile_options(cct PRIVATE ${PROJ_CXX_WARN_FLAGS}) + install(TARGETS cct - RUNTIME DESTINATION ${BINDIR}) + RUNTIME DESTINATION ${BINDIR}) if(MSVC AND BUILD_LIBPROJ_SHARED) - target_compile_definitions(cct PRIVATE PROJ_MSVC_DLL_IMPORT=1) + target_compile_definitions(cct PRIVATE PROJ_MSVC_DLL_IMPORT=1) endif() diff --git a/src/bin_cs2cs.cmake b/src/bin_cs2cs.cmake index d520192c..d2bb3b97 100644 --- a/src/bin_cs2cs.cmake +++ b/src/bin_cs2cs.cmake @@ -1,14 +1,18 @@ -set(CS2CS_SRC apps/cs2cs.cpp - apps/emess.cpp +set(CS2CS_SRC + apps/cs2cs.cpp + apps/emess.cpp + apps/utils.cpp ) source_group("Source Files\\Bin" FILES ${CS2CS_SRC}) add_executable(cs2cs ${CS2CS_SRC} ${CS2CS_INCLUDE}) target_link_libraries(cs2cs ${PROJ_LIBRARIES}) -install(TARGETS cs2cs - RUNTIME DESTINATION ${BINDIR}) +target_compile_options(cs2cs PRIVATE ${PROJ_CXX_WARN_FLAGS}) + +install(TARGETS cs2cs + RUNTIME DESTINATION ${BINDIR}) if(MSVC AND BUILD_LIBPROJ_SHARED) - target_compile_definitions(cs2cs PRIVATE PROJ_MSVC_DLL_IMPORT=1) + target_compile_definitions(cs2cs PRIVATE PROJ_MSVC_DLL_IMPORT=1) endif() diff --git a/src/bin_geod.cmake b/src/bin_geod.cmake index 049da318..84d2cd5b 100644 --- a/src/bin_geod.cmake +++ b/src/bin_geod.cmake @@ -1,18 +1,20 @@ -set(GEOD_SRC apps/geod.cpp - apps/geod_set.cpp - apps/geod_interface.cpp - apps/emess.cpp +set(GEOD_SRC + apps/geod.cpp + apps/geod_set.cpp + apps/geod_interface.cpp + apps/emess.cpp ) set(GEOD_INCLUDE apps/geod_interface.h) source_group("Source Files\\Bin" FILES ${GEOD_SRC} ${GEOD_INCLUDE}) -#Executable add_executable(geod ${GEOD_SRC} ${GEOD_INCLUDE}) target_link_libraries(geod ${PROJ_LIBRARIES}) +target_compile_options(geod PRIVATE ${PROJ_CXX_WARN_FLAGS}) + install(TARGETS geod - RUNTIME DESTINATION ${BINDIR}) + RUNTIME DESTINATION ${BINDIR}) if(MSVC AND BUILD_LIBPROJ_SHARED) - target_compile_definitions(geod PRIVATE PROJ_MSVC_DLL_IMPORT=1) + target_compile_definitions(geod PRIVATE PROJ_MSVC_DLL_IMPORT=1) endif() diff --git a/src/bin_geodtest.cmake b/src/bin_geodtest.cmake index 31de499d..c911e95f 100644 --- a/src/bin_geodtest.cmake +++ b/src/bin_geodtest.cmake @@ -1,16 +1,15 @@ -set(GEODTEST_SRC tests/geodtest.cpp ) +set(GEODTEST_SRC tests/geodtest.cpp) set(GEODTEST_INCLUDE) source_group("Source Files\\Bin" FILES ${GEODTEST_SRC} ${GEODTEST_INCLUDE}) -#Executable add_executable(geodtest ${GEODTEST_SRC} ${GEODTEST_INCLUDE}) target_link_libraries(geodtest ${PROJ_LIBRARIES}) -# Do not install +target_compile_options(geodtest PRIVATE ${PROJ_CXX_WARN_FLAGS}) -# Instead run as a test -add_test (NAME geodesic-test COMMAND geodtest) +# Do not install, instead run as a test +add_test(NAME geodesic-test COMMAND geodtest) if(MSVC AND BUILD_LIBPROJ_SHARED) - target_compile_definitions(geodtest PRIVATE PROJ_MSVC_DLL_IMPORT=1) + target_compile_definitions(geodtest PRIVATE PROJ_MSVC_DLL_IMPORT=1) endif() diff --git a/src/bin_gie.cmake b/src/bin_gie.cmake index 497315f9..49c57483 100644 --- a/src/bin_gie.cmake +++ b/src/bin_gie.cmake @@ -1,15 +1,19 @@ -set(GIE_SRC apps/gie.cpp - apps/proj_strtod.cpp - apps/proj_strtod.h) +set(GIE_SRC + apps/gie.cpp + apps/proj_strtod.cpp + apps/proj_strtod.h +) set(GIE_INCLUDE apps/optargpm.h) source_group("Source Files\\Bin" FILES ${GIE_SRC}) add_executable(gie ${GIE_SRC} ${GIE_INCLUDE}) target_link_libraries(gie ${PROJ_LIBRARIES}) +target_compile_options(gie PRIVATE ${PROJ_CXX_WARN_FLAGS}) + install(TARGETS gie - RUNTIME DESTINATION ${BINDIR}) + RUNTIME DESTINATION ${BINDIR}) if(MSVC AND BUILD_LIBPROJ_SHARED) - target_compile_definitions(gie PRIVATE PROJ_MSVC_DLL_IMPORT=1) + target_compile_definitions(gie PRIVATE PROJ_MSVC_DLL_IMPORT=1) endif() diff --git a/src/bin_proj.cmake b/src/bin_proj.cmake index 76e2ae9f..ce282fc6 100644 --- a/src/bin_proj.cmake +++ b/src/bin_proj.cmake @@ -1,18 +1,21 @@ -set(PROJ_SRC apps/proj.cpp - apps/emess.cpp +set(PROJ_SRC + apps/proj.cpp + apps/emess.cpp + apps/utils.cpp ) source_group("Source Files\\Bin" FILES ${PROJ_SRC}) -#Executable add_executable(binproj ${PROJ_SRC}) set_target_properties(binproj - PROPERTIES - OUTPUT_NAME proj) + PROPERTIES + OUTPUT_NAME proj) target_link_libraries(binproj ${PROJ_LIBRARIES}) -install(TARGETS binproj - RUNTIME DESTINATION ${BINDIR}) +target_compile_options(binproj PRIVATE ${PROJ_CXX_WARN_FLAGS}) + +install(TARGETS binproj + RUNTIME DESTINATION ${BINDIR}) if(MSVC AND BUILD_LIBPROJ_SHARED) - target_compile_definitions(binproj PRIVATE PROJ_MSVC_DLL_IMPORT=1) + target_compile_definitions(binproj PRIVATE PROJ_MSVC_DLL_IMPORT=1) endif() diff --git a/src/bin_projinfo.cmake b/src/bin_projinfo.cmake index ea6f1006..c2447262 100644 --- a/src/bin_projinfo.cmake +++ b/src/bin_projinfo.cmake @@ -2,15 +2,16 @@ set(PROJINFO_SRC apps/projinfo.cpp) source_group("Source Files\\Bin" FILES ${PROJINFO_SRC}) -#Executable add_executable(binprojinfo ${PROJINFO_SRC}) set_target_properties(binprojinfo - PROPERTIES - OUTPUT_NAME projinfo) + PROPERTIES + OUTPUT_NAME projinfo) target_link_libraries(binprojinfo ${PROJ_LIBRARIES}) -install(TARGETS binprojinfo - RUNTIME DESTINATION ${BINDIR}) +target_compile_options(binprojinfo PRIVATE ${PROJ_CXX_WARN_FLAGS}) + +install(TARGETS binprojinfo + RUNTIME DESTINATION ${BINDIR}) if(MSVC AND BUILD_LIBPROJ_SHARED) - target_compile_definitions(binprojinfo PRIVATE PROJ_MSVC_DLL_IMPORT=1) + target_compile_definitions(binprojinfo PRIVATE PROJ_MSVC_DLL_IMPORT=1) endif() diff --git a/src/conversions/axisswap.cpp b/src/conversions/axisswap.cpp index 97c8899a..15ec016b 100644 --- a/src/conversions/axisswap.cpp +++ b/src/conversions/axisswap.cpp @@ -59,7 +59,6 @@ operation: #include "proj.h" #include "proj_internal.h" -#include "proj_internal.h" PROJ_HEAD(axisswap, "Axis ordering"); diff --git a/src/conversions/cart.cpp b/src/conversions/cart.cpp index d9aea9b8..c1f6f09d 100644 --- a/src/conversions/cart.cpp +++ b/src/conversions/cart.cpp @@ -43,7 +43,6 @@ #define PJ_LIB__ #include "proj_internal.h" -#include "proj_internal.h" #include "proj_math.h" PROJ_HEAD(cart, "Geodetic/cartesian conversions"); @@ -163,6 +162,12 @@ static PJ_LPZ geodetic (PJ_XYZ cart, PJ *P) { c = cos(theta); s = sin(theta); lpz.phi = atan2 (cart.z + P->e2s*P->b*s*s*s, p - P->es*P->a*c*c*c); + if( fabs(lpz.phi) > M_HALFPI ) { + // this happen on non-sphere ellipsoid when x,y,z is very close to 0 + // there is no single solution to the cart->geodetic conversion in + // that case, so arbitrarily pickup phi = 0. + lpz.phi = 0; + } lpz.lam = atan2 (cart.y, cart.x); N = normal_radius_of_curvature (P->a, P->es, lpz.phi); diff --git a/src/conversions/geoc.cpp b/src/conversions/geoc.cpp index e0ca3df3..3d86b531 100644 --- a/src/conversions/geoc.cpp +++ b/src/conversions/geoc.cpp @@ -32,7 +32,6 @@ #include "proj.h" #include "proj_internal.h" -#include "proj_internal.h" PROJ_HEAD(geoc, "Geocentric Latitude"); diff --git a/src/conversions/noop.cpp b/src/conversions/noop.cpp new file mode 100644 index 00000000..a5dd6023 --- /dev/null +++ b/src/conversions/noop.cpp @@ -0,0 +1,19 @@ +#define PJ_LIB__ + +#include "proj_internal.h" + +PROJ_HEAD(noop, "No operation"); + +static PJ_COORD noop(PJ_COORD coord, PJ *P) { + (void) P; + return coord; +} + +PJ *CONVERSION(noop, 0) { + P->fwd4d = noop; + P->inv4d = noop; + P->left = PJ_IO_UNITS_WHATEVER; + P->right = PJ_IO_UNITS_WHATEVER; + return P; +} + diff --git a/src/conversions/unitconvert.cpp b/src/conversions/unitconvert.cpp index 1e3372d6..7ef07311 100644 --- a/src/conversions/unitconvert.cpp +++ b/src/conversions/unitconvert.cpp @@ -72,7 +72,6 @@ Last update: 2017-05-16 #include "proj_internal.h" #include "proj_math.h" -#include "proj_internal.h" PROJ_HEAD(unitconvert, "Unit conversion"); @@ -473,11 +472,11 @@ PJ *CONVERSION(unitconvert,0) { if (f != 0.0) { proj_log_debug(P, "xy_in unit: %s", normalized_name); } else { - if ( (f = pj_param (P->ctx, P->params, "dxy_in").f) == 0.0) + f = pj_param (P->ctx, P->params, "dxy_in").f; + if (f == 0.0 || 1.0 / f == 0.0) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); } - if (f != 0.0) - Q->xy_factor *= f; + Q->xy_factor = f; if (normalized_name != nullptr && strcmp(normalized_name, "Radian") == 0) P->left = PJ_IO_UNITS_RADIANS; } @@ -488,11 +487,11 @@ PJ *CONVERSION(unitconvert,0) { if (f != 0.0) { proj_log_debug(P, "xy_out unit: %s", normalized_name); } else { - if ( (f = pj_param (P->ctx, P->params, "dxy_out").f) == 0.0) + f = pj_param (P->ctx, P->params, "dxy_out").f; + if (f == 0.0 || 1.0 / f == 0.0) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); } - if (f != 0.0) - Q->xy_factor /= f; + Q->xy_factor /= f; if (normalized_name != nullptr && strcmp(normalized_name, "Radian") == 0) P->right= PJ_IO_UNITS_RADIANS; } @@ -509,11 +508,11 @@ PJ *CONVERSION(unitconvert,0) { if (f != 0.0) { proj_log_debug(P, "z_in unit: %s", normalized_name); } else { - if ( (f = pj_param (P->ctx, P->params, "dz_in").f) == 0.0) + f = pj_param (P->ctx, P->params, "dz_in").f; + if (f == 0.0 || 1.0 / f == 0.0) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); } - if (f != 0.0) - Q->z_factor *= f; + Q->z_factor = f; } if ((name = pj_param (P->ctx, P->params, "sz_out").s) != nullptr) { @@ -522,11 +521,11 @@ PJ *CONVERSION(unitconvert,0) { if (f != 0.0) { proj_log_debug(P, "z_out unit: %s", normalized_name); } else { - if ( (f = pj_param (P->ctx, P->params, "dz_out").f) == 0.0) + f = pj_param (P->ctx, P->params, "dz_out").f; + if (f == 0.0 || 1.0 / f == 0.0) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); } - if (f != 0.0) - Q->z_factor /= f; + Q->z_factor /= f; } if( z_in_is_linear >= 0 && z_out_is_linear >= 0 && diff --git a/src/ell_set.cpp b/src/ell_set.cpp index 4c9fc892..0d7fb6d5 100644 --- a/src/ell_set.cpp +++ b/src/ell_set.cpp @@ -6,7 +6,6 @@ #include "proj.h" #include "proj_internal.h" -#include "proj_internal.h" /* Prototypes of the pj_ellipsoid helper functions */ @@ -280,8 +279,8 @@ static int ellps_shape (PJ *P) { P->es = pj_atof (pj_param_value (par)); if (HUGE_VAL==P->es) return proj_errno_set (P, PJD_ERR_INVALID_ARG); - if (1==P->es) - return proj_errno_set (P, PJD_ERR_ECCENTRICITY_IS_ONE); + if (P->es >= 1) + return proj_errno_set (P, PJD_ERR_INVALID_ECCENTRICITY); break; /* eccentricity, e */ @@ -289,10 +288,8 @@ static int ellps_shape (PJ *P) { P->e = pj_atof (pj_param_value (par)); if (HUGE_VAL==P->e) return proj_errno_set (P, PJD_ERR_INVALID_ARG); - if (0==P->e) - return proj_errno_set (P, PJD_ERR_INVALID_ARG); - if (1==P->e) - return proj_errno_set (P, PJD_ERR_ECCENTRICITY_IS_ONE); + if (P->e < 0 || P->e >= 1) + return proj_errno_set (P, PJD_ERR_INVALID_ECCENTRICITY); P->es = P->e * P->e; break; @@ -301,8 +298,8 @@ static int ellps_shape (PJ *P) { P->b = pj_atof (pj_param_value (par)); if (HUGE_VAL==P->b) return proj_errno_set (P, PJD_ERR_INVALID_ARG); - if (0==P->b) - return proj_errno_set (P, PJD_ERR_ECCENTRICITY_IS_ONE); + if (P->b <= 0) + return proj_errno_set (P, PJD_ERR_INVALID_ECCENTRICITY); if (P->b==P->a) break; P->f = (P->a - P->b) / P->a; @@ -399,6 +396,10 @@ static int ellps_spherification (PJ *P) { break; } + if (P->a <= 0.) { + return proj_errno_set(P, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); + } + /* Clean up the ellipsoidal parameters to reflect the sphere */ P->es = P->e = P->f = 0; P->rf = HUGE_VAL; @@ -538,6 +539,10 @@ int pj_calc_ellipsoid_params (PJ *P, double a, double es) { /* flattening */ 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); + return PJD_ERR_INVALID_ECCENTRICITY; + } P->rf = P->f != 0.0 ? 1.0/P->f: HUGE_VAL; /* second flattening */ @@ -556,8 +561,8 @@ 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_ECCENTRICITY_IS_ONE); - return PJD_ERR_ECCENTRICITY_IS_ONE; + pj_ctx_set_errno( P->ctx, PJD_ERR_INVALID_ECCENTRICITY); + return PJD_ERR_INVALID_ECCENTRICITY; } P->rone_es = 1./P->one_es; @@ -644,6 +649,10 @@ int pj_ell_set (projCtx ctx, paralist *pl, double *a, double *es) { *es = pj_param(ctx,pl, "des").f; 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); + return 1; + } *es = e * e; } else if (pj_param(ctx,pl, "trf").i) { /* recip flattening */ *es = pj_param(ctx,pl, "drf").f; @@ -712,6 +721,10 @@ bomb: pj_ctx_set_errno(ctx, PJD_ERR_ES_LESS_THAN_ZERO); return 1; } + if (*es >= 1.) { + pj_ctx_set_errno(ctx, PJD_ERR_INVALID_ECCENTRICITY); + return 1; + } if (*a <= 0.) { pj_ctx_set_errno(ctx, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); return 1; diff --git a/src/factors.cpp b/src/factors.cpp index f50c8e21..7c59ee7a 100644 --- a/src/factors.cpp +++ b/src/factors.cpp @@ -3,7 +3,6 @@ #include "proj.h" #include "proj_internal.h" #include "proj_math.h" -#include "proj_internal.h" #include <errno.h> diff --git a/src/fwd.cpp b/src/fwd.cpp index a8c51934..c267045a 100644 --- a/src/fwd.cpp +++ b/src/fwd.cpp @@ -33,7 +33,6 @@ #include "proj_internal.h" #include "proj_math.h" -#include "proj_internal.h" #define INPUT_UNITS P->left #define OUTPUT_UNITS P->right diff --git a/src/gauss.cpp b/src/gauss.cpp index b7a27191..a34a8f5b 100644 --- a/src/gauss.cpp +++ b/src/gauss.cpp @@ -65,9 +65,19 @@ void *pj_gauss_ini(double e, double phi0, double *chi, double *rc) { } *chi = asin(sphi / en->C); en->ratexp = 0.5 * en->C * e; - en->K = tan(.5 * *chi + M_FORTPI) / ( - pow(tan(.5 * phi0 + M_FORTPI), en->C) * - srat(en->e * sphi, en->ratexp) ); + double srat_val = srat(en->e * sphi, en->ratexp); + if (srat_val == 0.0) { + free(en); + return nullptr; + } + if( .5 * phi0 + M_FORTPI < 1e-10 ) { + en->K = 1.0 / srat_val; + } + else { + en->K = tan(.5 * *chi + M_FORTPI) / ( + pow(tan(.5 * phi0 + M_FORTPI), en->C) * + srat_val ); + } return ((void *)en); } diff --git a/src/general_doc.dox b/src/general_doc.dox index ce5a8130..04248ae5 100644 --- a/src/general_doc.dox +++ b/src/general_doc.dox @@ -4,7 +4,7 @@ \section general_api_design General API design -The design of the class hierarchy is strongly derived from \ref ISO_19111_2018. +The design of the class hierarchy is strongly derived from \ref ISO_19111_2019. Classes for which the constructors are not directly accessible have their instances constructed with create() methods. The returned object is a non-null @@ -78,13 +78,12 @@ Coordinate Reference Systems (CRS), coordinate systems (CS) and coordinate transformation or coordinate conversion between two different coordinate reference systems. -\subsubsection ISO_19111_2018 ISO 19111:2018 +\subsubsection ISO_19111_2019 ISO 19111:2019 This is the revision mostly used for PROJ C++ modelling. -[OGC 18-005r1, 2018-04-04, ISO 19111:2018] -(https://portal.opengeospatial.org/files/?artifact_id=78556) -(not yet adopted, at time of writing) +[OGC 18-005r4, 2019-02-08, ISO 19111:2019] +(http://docs.opengeospatial.org/as/18-005r4/18-005r4.html) \subsubsection ISO_19111_2007 ISO 19111:2007 @@ -111,7 +110,7 @@ PROJ implements the two following revisions of the standard: \subsubsection WKT2_2015 WKT2:2015 -[OGC 12-063r5, 2015-05-01, WKT2-2015] +[OGC 12-063r5, 2015-05-01, ISO 19162:2015(E), WKT2-2015] (http://docs.opengeospatial.org/is/12-063r5/12-063r5.html) \subsection WKT1 WKT1 specification diff --git a/src/gridcatalog.cpp b/src/gridcatalog.cpp index ca5750ab..15d81dd7 100644 --- a/src/gridcatalog.cpp +++ b/src/gridcatalog.cpp @@ -37,6 +37,13 @@ static PJ_GridCatalog *grid_catalog_list = nullptr; +static +PJ_GRIDINFO *pj_gc_findgrid( projCtx_t *ctx, + PJ_GridCatalog *catalog, int after, + PJ_LP location, double date, + PJ_Region *optional_region, + double *grid_date ); + /************************************************************************/ /* pj_gc_unloadall() */ /* */ @@ -236,6 +243,7 @@ int pj_gc_apply_gridshift( PJ *defn, int inverse, /* pj_c_findgrid() */ /************************************************************************/ +static PJ_GRIDINFO *pj_gc_findgrid( projCtx ctx, PJ_GridCatalog *catalog, int after, PJ_LP location, double date, PJ_Region *optional_region, @@ -287,6 +295,8 @@ PJ_GRIDINFO *pj_gc_findgrid( projCtx ctx, PJ_GridCatalog *catalog, int after, int grid_count = 0; gridlist = pj_gridlist_from_nadgrids( ctx, entry->definition, &grid_count); + // FIXME: this leaks gridlist itself, and memory ownership of + // entry->gridinfo is also confusing. Coverity CID 193539 if( grid_count == 1 ) entry->gridinfo = gridlist[0]; } diff --git a/src/gridinfo.cpp b/src/gridinfo.cpp index 14759557..7f7d930f 100644 --- a/src/gridinfo.cpp +++ b/src/gridinfo.cpp @@ -36,7 +36,6 @@ #include <string.h> #include "proj_internal.h" -#include "proj_internal.h" /************************************************************************/ /* swap_words() */ @@ -851,7 +850,6 @@ static int pj_gridinfo_init_gtx( projCtx ctx, PAFile fid, PJ_GRIDINFO *gi ) PJ_GRIDINFO *pj_gridinfo_init( projCtx ctx, const char *gridname ) { - char fname[MAX_PATH_FILENAME+1]; PJ_GRIDINFO *gilist; PAFile fp; char header[160]; @@ -885,13 +883,12 @@ PJ_GRIDINFO *pj_gridinfo_init( projCtx ctx, const char *gridname ) /* -------------------------------------------------------------------- */ /* Open the file using the usual search rules. */ /* -------------------------------------------------------------------- */ - strcpy(fname, gridname); - if (!(fp = pj_open_lib(ctx, fname, "rb"))) { + if (!(fp = pj_open_lib(ctx, gridname, "rb"))) { ctx->last_errno = 0; /* don't treat as a persistent error */ return gilist; } - gilist->filename = pj_strdup(fname); + gilist->filename = pj_strdup(gridname); if (!gilist->filename) { pj_dalloc(gilist->gridname); pj_dalloc(gilist); diff --git a/src/init.cpp b/src/init.cpp index 2961bcca..ba9cddd2 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -40,7 +40,6 @@ #include "proj.h" #include "proj_internal.h" #include "proj_math.h" -#include "proj_internal.h" /**************************************************************************************/ @@ -673,14 +672,14 @@ pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_i if (PJD_ERR_MAJOR_AXIS_NOT_GIVEN==proj_errno (PIN)) proj_errno_reset (PIN); PIN->f = 1.0/298.257223563; - PIN->a_orig = PIN->a = 6378137.0; - PIN->es_orig = PIN->es = PIN->f*(2-PIN->f); + PIN->a = 6378137.0; + PIN->es = PIN->f*(2-PIN->f); } } PIN->a_orig = PIN->a; PIN->es_orig = PIN->es; if (pj_calc_ellipsoid_params (PIN, PIN->a, PIN->es)) - return pj_default_destructor (PIN, PJD_ERR_ECCENTRICITY_IS_ONE); + return pj_default_destructor (PIN, PJD_ERR_INVALID_ECCENTRICITY); /* Now that we have ellipse information check for WGS84 datum */ if( PIN->datum_type == PJD_3PARAM @@ -737,6 +736,8 @@ pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_i /* Central latitude */ PIN->phi0 = pj_param(ctx, start, "rlat_0").f; + if( fabs(PIN->phi0) > M_HALFPI ) + return pj_default_destructor (PIN, PJD_ERR_LAT_LARGER_THAN_90); /* False easting and northing */ PIN->x0 = pj_param(ctx, start, "dx_0").f; diff --git a/src/internal.cpp b/src/internal.cpp index 44246842..b4b7a683 100644 --- a/src/internal.cpp +++ b/src/internal.cpp @@ -491,9 +491,7 @@ void proj_log_func (PJ_CONTEXT *ctx, void *app_data, PJ_LOG_FUNCTION logf) { passed as first arg at each call to the logger ******************************************************************************/ if (nullptr==ctx) - pj_get_default_ctx (); - if (nullptr==ctx) - return; + ctx = pj_get_default_ctx (); ctx->logger_app_data = app_data; if (nullptr!=logf) ctx->logger = logf; diff --git a/src/inv.cpp b/src/inv.cpp index a05f8376..b9520c53 100644 --- a/src/inv.cpp +++ b/src/inv.cpp @@ -32,7 +32,6 @@ #include "proj_internal.h" #include "proj_math.h" -#include "proj_internal.h" #define INPUT_UNITS P->right #define OUTPUT_UNITS P->left diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index b3f200fe..5d2216e8 100644 --- a/src/iso19111/c_api.cpp +++ b/src/iso19111/c_api.cpp @@ -30,10 +30,12 @@ #define FROM_PROJ_CPP #endif +#include <algorithm> #include <cassert> #include <cstdarg> #include <cstring> #include <map> +#include <memory> #include <new> #include <utility> #include <vector> @@ -77,6 +79,11 @@ 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); + 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); + } } // --------------------------------------------------------------------------- @@ -134,8 +141,7 @@ static PJ *pj_obj_create(PJ_CONTEXT *ctx, const IdentifiedObjectNNPtr &objIn) { auto formatter = PROJStringFormatter::create( PROJStringFormatter::Convention::PROJ_5, dbContext); auto projString = coordop->exportToPROJString(formatter.get()); - auto pj = pj_create_internal( - ctx, projString.empty() ? "+proj=affine" : projString.c_str()); + auto pj = pj_create_internal(ctx, projString.c_str()); if (pj) { pj->iso_obj = objIn; return pj; @@ -147,6 +153,7 @@ static PJ *pj_obj_create(PJ_CONTEXT *ctx, const IdentifiedObjectNNPtr &objIn) { } auto pj = pj_new(); if (pj) { + pj->ctx = ctx; pj->descr = "ISO-19111 object"; pj->iso_obj = objIn; } @@ -975,29 +982,18 @@ int proj_is_equivalent_to(const PJ *obj, const PJ *other, return false; } - // Make sure that the C and C++ enumerations match - static_assert(static_cast<int>(PJ_COMP_STRICT) == - static_cast<int>(IComparable::Criterion::STRICT), - ""); - static_assert(static_cast<int>(PJ_COMP_EQUIVALENT) == - static_cast<int>(IComparable::Criterion::EQUIVALENT), - ""); - static_assert( - static_cast<int>(PJ_COMP_EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS) == - static_cast<int>( - IComparable::Criterion::EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS), - ""); + const auto cppCriterion = ([](PJ_COMPARISON_CRITERION l_criterion) { + switch (l_criterion) { + case PJ_COMP_STRICT: + return IComparable::Criterion::STRICT; + case PJ_COMP_EQUIVALENT: + return IComparable::Criterion::EQUIVALENT; + case PJ_COMP_EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS: + break; + } + return IComparable::Criterion::EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS; + })(criterion); - // Make sure we enumerate all values. If adding a new value, as we - // don't have a default clause, the compiler will warn. - switch (criterion) { - case PJ_COMP_STRICT: - case PJ_COMP_EQUIVALENT: - case PJ_COMP_EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS: - break; - } - const IComparable::Criterion cppCriterion = - static_cast<IComparable::Criterion>(criterion); return obj->iso_obj->isEquivalentTo(other->iso_obj.get(), cppCriterion); } @@ -1121,40 +1117,24 @@ const char *proj_as_wkt(PJ_CONTEXT *ctx, const PJ *obj, PJ_WKT_TYPE type, return nullptr; } - // Make sure that the C and C++ enumerations match - static_assert(static_cast<int>(PJ_WKT2_2015) == - static_cast<int>(WKTFormatter::Convention::WKT2_2015), - ""); - static_assert( - static_cast<int>(PJ_WKT2_2015_SIMPLIFIED) == - static_cast<int>(WKTFormatter::Convention::WKT2_2015_SIMPLIFIED), - ""); - static_assert(static_cast<int>(PJ_WKT2_2018) == - static_cast<int>(WKTFormatter::Convention::WKT2_2018), - ""); - static_assert( - static_cast<int>(PJ_WKT2_2018_SIMPLIFIED) == - static_cast<int>(WKTFormatter::Convention::WKT2_2018_SIMPLIFIED), - ""); - static_assert(static_cast<int>(PJ_WKT1_GDAL) == - static_cast<int>(WKTFormatter::Convention::WKT1_GDAL), - ""); - static_assert(static_cast<int>(PJ_WKT1_ESRI) == - static_cast<int>(WKTFormatter::Convention::WKT1_ESRI), - ""); - // Make sure we enumerate all values. If adding a new value, as we - // don't have a default clause, the compiler will warn. - switch (type) { - case PJ_WKT2_2015: - case PJ_WKT2_2015_SIMPLIFIED: - case PJ_WKT2_2018: - case PJ_WKT2_2018_SIMPLIFIED: - case PJ_WKT1_GDAL: - case PJ_WKT1_ESRI: - break; - } - const WKTFormatter::Convention convention = - static_cast<WKTFormatter::Convention>(type); + const auto convention = ([](PJ_WKT_TYPE l_type) { + switch (l_type) { + case PJ_WKT2_2015: + return WKTFormatter::Convention::WKT2_2015; + case PJ_WKT2_2015_SIMPLIFIED: + return WKTFormatter::Convention::WKT2_2015_SIMPLIFIED; + case PJ_WKT2_2018: + return WKTFormatter::Convention::WKT2_2018; + case PJ_WKT2_2018_SIMPLIFIED: + return WKTFormatter::Convention::WKT2_2018_SIMPLIFIED; + case PJ_WKT1_GDAL: + return WKTFormatter::Convention::WKT1_GDAL; + case PJ_WKT1_ESRI: + break; + } + return WKTFormatter::Convention::WKT1_ESRI; + })(type); + try { auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); auto formatter = WKTFormatter::create(convention, dbContext); @@ -1365,7 +1345,7 @@ static const GeodeticCRS *extractGeodeticCRS(PJ_CONTEXT *ctx, const PJ *crs, * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param crs Objet of type CRS (must not be NULL) + * @param crs Object of type CRS (must not be NULL) * @return Object that must be unreferenced with proj_destroy(), or NULL * in case of error. */ @@ -1389,7 +1369,7 @@ PJ *proj_crs_get_geodetic_crs(PJ_CONTEXT *ctx, const PJ *crs) { * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param crs Objet of type CRS (must not be NULL) + * @param crs Object of type CRS (must not be NULL) * @param index Index of the CRS component (typically 0 = horizontal, 1 = * vertical) * @return Object that must be unreferenced with proj_destroy(), or NULL @@ -1471,7 +1451,7 @@ PJ *proj_crs_create_bound_crs(PJ_CONTEXT *ctx, const PJ *base_crs, * osgeo::proj::crs::CRS::createBoundCRSToWGS84IfPossible() * * @param ctx PROJ context, or NULL for default context - * @param crs Objet of type CRS (must not be NULL) + * @param crs Object of type CRS (must not be NULL) * @param options null-terminated list of options, or NULL. Currently * supported options are: * <ul> @@ -1530,7 +1510,7 @@ PJ *proj_crs_create_bound_crs_to_WGS84(PJ_CONTEXT *ctx, const PJ *crs, * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param obj Objet of type CRS or GeodeticReferenceFrame (must not be NULL) + * @param obj Object of type CRS or GeodeticReferenceFrame (must not be NULL) * @return Object that must be unreferenced with proj_destroy(), or NULL * in case of error. */ @@ -1562,7 +1542,7 @@ PJ *proj_get_ellipsoid(PJ_CONTEXT *ctx, const PJ *obj) { * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param crs Objet of type CRS (must not be NULL) + * @param crs Object of type CRS (must not be NULL) * @return Object that must be unreferenced with proj_destroy(), or NULL * in case of error. */ @@ -1645,7 +1625,7 @@ int proj_ellipsoid_get_parameters(PJ_CONTEXT *ctx, const PJ *ellipsoid, * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param obj Objet of type CRS or GeodeticReferenceFrame (must not be NULL) + * @param obj Object of type CRS or GeodeticReferenceFrame (must not be NULL) * @return Object that must be unreferenced with proj_destroy(), or NULL * in case of error. */ @@ -1720,7 +1700,7 @@ int proj_prime_meridian_get_parameters(PJ_CONTEXT *ctx, * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param obj Objet of type BoundCRS or CoordinateOperation (must not be NULL) + * @param obj Object of type BoundCRS or CoordinateOperation (must not be NULL) * @return Object that must be unreferenced with proj_destroy(), or NULL * in case of error, or missing source CRS. */ @@ -1763,7 +1743,7 @@ PJ *proj_get_source_crs(PJ_CONTEXT *ctx, const PJ *obj) { * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param obj Objet of type BoundCRS or CoordinateOperation (must not be NULL) + * @param obj Object of type BoundCRS or CoordinateOperation (must not be NULL) * @return Object that must be unreferenced with proj_destroy(), or NULL * in case of error, or missing target CRS. */ @@ -1797,7 +1777,7 @@ PJ *proj_get_target_crs(PJ_CONTEXT *ctx, const PJ *obj) { /** \brief Identify the CRS with reference CRSs. * * The candidate CRSs are either hard-coded, or looked in the database when - * authorityFactory is not null. + * it is available. * * The method returns a list of matching reference CRS, and the percentage * (0-100) of confidence in the match. The list is sorted by decreasing @@ -1950,7 +1930,7 @@ void proj_string_list_destroy(PROJ_STRING_LIST list) { // --------------------------------------------------------------------------- -/** \brief Instanciate a default set of parameters to be used by +/** \brief Instantiate a default set of parameters to be used by * proj_get_crs_list(). * * @return a new object to free with proj_get_crs_list_parameters_destroy() */ @@ -1987,7 +1967,7 @@ void proj_get_crs_list_parameters_destroy(PROJ_CRS_LIST_PARAMETERS *params) { * entry is NULL. This array should be freed with proj_crs_info_list_destroy() * * When no filter parameters are set, this is functionnaly equivalent to - * proj_get_crs_info_list_from_database(), instanciating a PJ* object for each + * proj_get_crs_info_list_from_database(), instantiating a PJ* object for each * of the proj_create_from_database() and retrieving information with the * various getters. However this function will be much faster. * @@ -2167,7 +2147,7 @@ void proj_crs_info_list_destroy(PROJ_CRS_INFO **list) { * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param crs Objet of type DerivedCRS or BoundCRSs (must not be NULL) + * @param crs Object of type DerivedCRS or BoundCRSs (must not be NULL) * @return Object of type SingleOperation that must be unreferenced with * proj_destroy(), or NULL in case of error. */ @@ -2198,7 +2178,7 @@ PJ *proj_crs_get_coordoperation(PJ_CONTEXT *ctx, const PJ *crs) { /** \brief Return information on the operation method of the SingleOperation. * * @param ctx PROJ context, or NULL for default context - * @param coordoperation Objet of type SingleOperation (typically a Conversion + * @param coordoperation Object of type SingleOperation (typically a Conversion * or Transformation) (must not be NULL) * @param out_method_name Pointer to a string value to store the method * (projection) name. or NULL @@ -5729,12 +5709,12 @@ PJ *proj_create_conversion_equal_earth(PJ_CONTEXT *ctx, double center_long, * available. * * @param ctx PROJ context, or NULL for default context - * @param coordoperation Objet of type CoordinateOperation or derived classes + * @param coordoperation Object of type CoordinateOperation or derived classes * (must not be NULL) * @return TRUE or FALSE. */ -int proj_coordoperation_is_instanciable(PJ_CONTEXT *ctx, +int proj_coordoperation_is_instantiable(PJ_CONTEXT *ctx, const PJ *coordoperation) { assert(coordoperation); auto op = dynamic_cast<const CoordinateOperation *>( @@ -5746,7 +5726,7 @@ int proj_coordoperation_is_instanciable(PJ_CONTEXT *ctx, } auto dbContext = getDBcontextNoException(ctx, __FUNCTION__); try { - return op->isPROJInstanciable(dbContext) ? 1 : 0; + return op->isPROJInstantiable(dbContext) ? 1 : 0; } catch (const std::exception &) { return 0; } @@ -5754,10 +5734,40 @@ int proj_coordoperation_is_instanciable(PJ_CONTEXT *ctx, // --------------------------------------------------------------------------- +/** \brief Return whether a coordinate operation has a "ballpark" + * transformation, + * that is a very approximate one, due to lack of more accurate transformations. + * + * Typically a null geographic offset between two horizontal datum, or a + * null vertical offset (or limited to unit changes) between two vertical + * datum. Errors of several tens to one hundred meters might be expected, + * compared to more accurate transformations. + * + * @param ctx PROJ context, or NULL for default context + * @param coordoperation Object of type CoordinateOperation or derived classes + * (must not be NULL) + * @return TRUE or FALSE. + */ + +int proj_coordoperation_has_ballpark_transformation(PJ_CONTEXT *ctx, + const PJ *coordoperation) { + assert(coordoperation); + auto op = dynamic_cast<const CoordinateOperation *>( + coordoperation->iso_obj.get()); + if (!op) { + proj_log_error(ctx, __FUNCTION__, + "Object is not a CoordinateOperation"); + return 0; + } + return op->hasBallparkTransformation(); +} + +// --------------------------------------------------------------------------- + /** \brief Return the number of parameters of a SingleOperation * * @param ctx PROJ context, or NULL for default context - * @param coordoperation Objet of type SingleOperation or derived classes + * @param coordoperation Object of type SingleOperation or derived classes * (must not be NULL) */ @@ -5779,7 +5789,7 @@ int proj_coordoperation_get_param_count(PJ_CONTEXT *ctx, /** \brief Return the index of a parameter of a SingleOperation * * @param ctx PROJ context, or NULL for default context - * @param coordoperation Objet of type SingleOperation or derived classes + * @param coordoperation Object of type SingleOperation or derived classes * (must not be NULL) * @param name Parameter name. Must not be NULL * @return index (>=0), or -1 in case of error. @@ -5812,7 +5822,7 @@ int proj_coordoperation_get_param_index(PJ_CONTEXT *ctx, /** \brief Return a parameter of a SingleOperation * * @param ctx PROJ context, or NULL for default context - * @param coordoperation Objet of type SingleOperation or derived classes + * @param coordoperation Object of type SingleOperation or derived classes * (must not be NULL) * @param index Parameter index. * @param out_name Pointer to a string value to store the parameter name. or @@ -5952,10 +5962,14 @@ int proj_coordoperation_get_param( * values. * * @param ctx PROJ context, or NULL for default context - * @param coordoperation Objet of type Transformation, that can be represented + * @param coordoperation Object of type Transformation, that can be represented * as a WKT1 TOWGS84 node (must not be NULL) * @param out_values Pointer to an array of value_count double values. - * @param value_count Size of out_values array. + * @param value_count Size of out_values array. The suggested size is 7 to get + * translation, rotation and scale difference parameters. Rotation and scale + * difference terms might be zero if the transformation only includes + * translation + * parameters. In that case, value_count could be set to 3. * @param emit_error_if_incompatible Boolean to inicate if an error must be * logged if coordoperation is not compatible with a WKT1 TOWGS84 * representation. @@ -5997,7 +6011,7 @@ int proj_coordoperation_get_towgs84_values(PJ_CONTEXT *ctx, /** \brief Return the number of grids used by a CoordinateOperation * * @param ctx PROJ context, or NULL for default context - * @param coordoperation Objet of type CoordinateOperation or derived classes + * @param coordoperation Object of type CoordinateOperation or derived classes * (must not be NULL) */ @@ -6033,7 +6047,7 @@ int proj_coordoperation_get_grid_used_count(PJ_CONTEXT *ctx, /** \brief Return a parameter of a SingleOperation * * @param ctx PROJ context, or NULL for default context - * @param coordoperation Objet of type SingleOperation or derived classes + * @param coordoperation Object of type SingleOperation or derived classes * (must not be NULL) * @param index Parameter index. * @param out_short_name Pointer to a string value to store the grid short name. @@ -6508,7 +6522,7 @@ proj_create_operations(PJ_CONTEXT *ctx, const PJ *source_crs, /** \brief Return the number of objects in the result set * - * @param result Objet of type PJ_OBJ_LIST (must not be NULL) + * @param result Object of type PJ_OBJ_LIST (must not be NULL) */ int proj_list_get_count(const PJ_OBJ_LIST *result) { assert(result); @@ -6524,7 +6538,7 @@ int proj_list_get_count(const PJ_OBJ_LIST *result) { * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param result Objet of type PJ_OBJ_LIST (must not be NULL) + * @param result Object of type PJ_OBJ_LIST (must not be NULL) * @param index Index * @return a new object that must be unreferenced with proj_destroy(), * or nullptr in case of error. @@ -6590,7 +6604,7 @@ double proj_coordoperation_get_accuracy(PJ_CONTEXT *ctx, * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param crs Objet of type SingleCRS (must not be NULL) + * @param crs Object of type SingleCRS (must not be NULL) * @return Object that must be unreferenced with proj_destroy(), or NULL * in case of error (or if there is no datum) */ @@ -6618,7 +6632,7 @@ PJ *proj_crs_get_datum(PJ_CONTEXT *ctx, const PJ *crs) { * It should be used by at most one thread at a time. * * @param ctx PROJ context, or NULL for default context - * @param crs Objet of type SingleCRS (must not be NULL) + * @param crs Object of type SingleCRS (must not be NULL) * @return Object that must be unreferenced with proj_destroy(), or NULL * in case of error. */ @@ -6638,7 +6652,7 @@ PJ *proj_crs_get_coordinate_system(PJ_CONTEXT *ctx, const PJ *crs) { /** \brief Returns the type of the coordinate system. * * @param ctx PROJ context, or NULL for default context - * @param cs Objet of type CoordinateSystem (must not be NULL) + * @param cs Object of type CoordinateSystem (must not be NULL) * @return type, or PJ_CS_TYPE_UNKNOWN in case of error. */ PJ_COORDINATE_SYSTEM_TYPE proj_cs_get_type(PJ_CONTEXT *ctx, const PJ *cs) { @@ -6684,7 +6698,7 @@ PJ_COORDINATE_SYSTEM_TYPE proj_cs_get_type(PJ_CONTEXT *ctx, const PJ *cs) { /** \brief Returns the number of axis of the coordinate system. * * @param ctx PROJ context, or NULL for default context - * @param cs Objet of type CoordinateSystem (must not be NULL) + * @param cs Object of type CoordinateSystem (must not be NULL) * @return number of axis, or -1 in case of error. */ int proj_cs_get_axis_count(PJ_CONTEXT *ctx, const PJ *cs) { @@ -6703,7 +6717,7 @@ int proj_cs_get_axis_count(PJ_CONTEXT *ctx, const PJ *cs) { /** \brief Returns information on an axis * * @param ctx PROJ context, or NULL for default context - * @param cs Objet of type CoordinateSystem (must not be NULL) + * @param cs Object of type CoordinateSystem (must not be NULL) * @param index Index of the coordinate system (between 0 and * proj_cs_get_axis_count() - 1) * @param out_name Pointer to a string value to store the axis name. or NULL @@ -6764,3 +6778,88 @@ int proj_cs_get_axis_info(PJ_CONTEXT *ctx, const PJ *cs, int index, } return true; } + +// --------------------------------------------------------------------------- + +/** \brief Returns a PJ* object whose axis order is the one expected for + * visualization purposes. + * + * The input object must be a coordinate operation, that has been created with + * proj_create_crs_to_crs(). + * If the axis order of its source or target CRS is northing,easting, then an + * axis swap operation will be inserted. + * + * @param ctx PROJ context, or NULL for default context + * @param obj Object of type CoordinateOperation, + * created with proj_create_crs_to_crs() (must not be NULL) + * @return a new PJ* object to free with proj_destroy() in case of success, or + * nullptr in case of error + */ +PJ *proj_normalize_for_visualization(PJ_CONTEXT *ctx, const PJ *obj) { + + SANITIZE_CTX(ctx); + if (!obj->alternativeCoordinateOperations.empty()) { + try { + auto pjNew = std::unique_ptr<PJ>(pj_new()); + if (!pjNew) + return nullptr; + pjNew->ctx = ctx; + for (const auto &alt : obj->alternativeCoordinateOperations) { + auto co = dynamic_cast<const CoordinateOperation *>( + alt.pj->iso_obj.get()); + if (co) { + double minxSrc = alt.minxSrc; + double minySrc = alt.minySrc; + double maxxSrc = alt.maxxSrc; + double maxySrc = alt.maxySrc; + double minxDst = alt.minxDst; + double minyDst = alt.minyDst; + double maxxDst = alt.maxxDst; + double maxyDst = alt.maxyDst; + + auto l_sourceCRS = co->sourceCRS(); + auto l_targetCRS = co->targetCRS(); + if (l_sourceCRS && l_targetCRS) { + const bool swapSource = + l_sourceCRS + ->mustAxisOrderBeSwitchedForVisualization(); + if (swapSource) { + std::swap(minxSrc, minySrc); + std::swap(maxxSrc, maxySrc); + } + const bool swapTarget = + l_targetCRS + ->mustAxisOrderBeSwitchedForVisualization(); + if (swapTarget) { + std::swap(minxDst, minyDst); + std::swap(maxxDst, maxyDst); + } + } + pjNew->alternativeCoordinateOperations.emplace_back( + minxSrc, minySrc, maxxSrc, maxySrc, minxDst, minyDst, + maxxDst, maxyDst, + pj_obj_create(ctx, co->normalizeForVisualization()), + co->nameStr()); + } + } + return pjNew.release(); + } catch (const std::exception &e) { + proj_log_debug(ctx, __FUNCTION__, e.what()); + return nullptr; + } + } + + auto co = dynamic_cast<const CoordinateOperation *>(obj->iso_obj.get()); + if (!co) { + proj_log_error(ctx, __FUNCTION__, "Object is not a CoordinateOperation " + "created with " + "proj_create_crs_to_crs"); + return nullptr; + } + try { + return pj_obj_create(ctx, co->normalizeForVisualization()); + } catch (const std::exception &e) { + proj_log_debug(ctx, __FUNCTION__, e.what()); + return nullptr; + } +} diff --git a/src/iso19111/common.cpp b/src/iso19111/common.cpp index bdd836e1..d46da0da 100644 --- a/src/iso19111/common.cpp +++ b/src/iso19111/common.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * * Project: PROJ - * Purpose: ISO19111:2018 implementation + * Purpose: ISO19111:2019 implementation * Author: Even Rouault <even dot rouault at spatialys dot com> * ****************************************************************************** @@ -641,7 +641,7 @@ const std::string &IdentifiedObject::remarks() PROJ_PURE_DEFN { /** \brief Return whether the object is deprecated. * - * \remark Extension of \ref ISO_19111_2018 + * \remark Extension of \ref ISO_19111_2019 */ bool IdentifiedObject::isDeprecated() PROJ_PURE_DEFN { return d->isDeprecated; } @@ -1073,7 +1073,7 @@ void ObjectUsage::setProperties( void ObjectUsage::baseExportToWKT(WKTFormatter *formatter) const { const bool isWKT2 = formatter->version() == WKTFormatter::Version::WKT2; - if (isWKT2 && formatter->outputId()) { + if (isWKT2 && formatter->outputUsage()) { auto l_domains = domains(); if (!l_domains.empty()) { if (formatter->use2018Keywords()) { diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 2128124b..348a776a 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * * Project: PROJ - * Purpose: ISO19111:2018 implementation + * Purpose: ISO19111:2019 implementation * Author: Even Rouault <even dot rouault at spatialys dot com> * ****************************************************************************** @@ -56,6 +56,10 @@ #include <string> #include <vector> +#ifdef DEBUG +#include <iostream> +#endif + using namespace NS_PROJ::internal; #if 0 @@ -104,8 +108,17 @@ constexpr double UTM_NORTH_FALSE_NORTHING = 0.0; constexpr double UTM_SOUTH_FALSE_NORTHING = 10000000.0; static const std::string INVERSE_OF = "Inverse of "; -static const char *NULL_GEOCENTRIC_TRANSLATION = "Null geocentric translation"; +static const char *BALLPARK_GEOCENTRIC_TRANSLATION = + "Ballpark geocentric translation"; static const char *NULL_GEOGRAPHIC_OFFSET = "Null geographic offset"; +static const char *BALLPARK_GEOGRAPHIC_OFFSET = "Ballpark geographic offset"; +static const char *BALLPARK_VERTICAL_TRANSFORMATION_PREFIX = + " (ballpark vertical transformation"; +static const char *BALLPARK_VERTICAL_TRANSFORMATION = + " (ballpark vertical transformation)"; +static const char *BALLPARK_VERTICAL_TRANSFORMATION_NO_ELLIPSOID_VERT_HEIGHT = + " (ballpark vertical transformation, without ellipsoid height to vertical " + "height correction)"; //! @endcond //! @cond Doxygen_Suppress @@ -513,6 +526,7 @@ struct CoordinateOperation::Private { crs::CRSPtr interpolationCRS_{}; util::optional<common::DataEpoch> sourceCoordinateEpoch_{}; util::optional<common::DataEpoch> targetCoordinateEpoch_{}; + bool hasBallparkTransformation_ = false; // do not set this for a ProjectedCRS.definingConversion struct CRSStrongRef { @@ -542,7 +556,9 @@ struct CoordinateOperation::Private { // --------------------------------------------------------------------------- -GridDescription::GridDescription() = default; +GridDescription::GridDescription() + : shortName{}, fullName{}, packageName{}, url{}, directDownload(false), + openLicense(false), available(false) {} GridDescription::~GridDescription() = default; @@ -706,7 +722,7 @@ void CoordinateOperation::setAccuracies( * a PROJ pipeline, checking in particular that referenced grids are * available. */ -bool CoordinateOperation::isPROJInstanciable( +bool CoordinateOperation::isPROJInstantiable( const io::DatabaseContextPtr &databaseContext) const { try { exportToPROJString(io::PROJStringFormatter::create().get()); @@ -723,6 +739,84 @@ bool CoordinateOperation::isPROJInstanciable( // --------------------------------------------------------------------------- +/** \brief Return whether a coordinate operation has a "ballpark" + * transformation, + * that is a very approximate one, due to lack of more accurate transformations. + * + * Typically a null geographic offset between two horizontal datum, or a + * null vertical offset (or limited to unit changes) between two vertical + * datum. Errors of several tens to one hundred meters might be expected, + * compared to more accurate transformations. + */ +bool CoordinateOperation::hasBallparkTransformation() const { + return d->hasBallparkTransformation_; +} + +// --------------------------------------------------------------------------- + +void CoordinateOperation::setHasBallparkTransformation(bool b) { + d->hasBallparkTransformation_ = b; +} + +// --------------------------------------------------------------------------- + +void CoordinateOperation::setProperties( + const util::PropertyMap &properties) // throw(InvalidValueTypeException) +{ + ObjectUsage::setProperties(properties); + properties.getStringValue(OPERATION_VERSION_KEY, d->operationVersion_); +} + +// --------------------------------------------------------------------------- + +/** \brief Return a variation of the current coordinate operation whose axis + * order is the one expected for visualization purposes. + */ +CoordinateOperationNNPtr +CoordinateOperation::normalizeForVisualization() const { + auto l_sourceCRS = sourceCRS(); + auto l_targetCRS = targetCRS(); + if (!l_sourceCRS || !l_targetCRS) { + throw util::UnsupportedOperationException( + "Cannot retrieve source or target CRS"); + } + const bool swapSource = + l_sourceCRS->mustAxisOrderBeSwitchedForVisualization(); + const bool swapTarget = + l_targetCRS->mustAxisOrderBeSwitchedForVisualization(); + auto l_this = NN_NO_CHECK(std::dynamic_pointer_cast<CoordinateOperation>( + shared_from_this().as_nullable())); + if (!swapSource && !swapTarget) { + return l_this; + } + std::vector<CoordinateOperationNNPtr> subOps; + if (swapSource) { + auto op = Conversion::createAxisOrderReversal(false); + op->setCRSs(l_sourceCRS->normalizeForVisualization(), + NN_NO_CHECK(l_sourceCRS), nullptr); + subOps.emplace_back(op); + } + subOps.emplace_back(l_this); + if (swapTarget) { + auto op = Conversion::createAxisOrderReversal(false); + op->setCRSs(NN_NO_CHECK(l_targetCRS), + l_targetCRS->normalizeForVisualization(), nullptr); + subOps.emplace_back(op); + } + return util::nn_static_pointer_cast<CoordinateOperation>( + ConcatenatedOperation::createComputeMetadata(subOps, true)); +} + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +CoordinateOperationNNPtr CoordinateOperation::shallowClone() const { + return _shallowClone(); +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress struct OperationMethod::Private { util::optional<std::string> formula_{}; @@ -1523,11 +1617,12 @@ static SingleOperationNNPtr createPROJBased( const util::PropertyMap &properties, const io::IPROJStringExportableNNPtr &projExportable, const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, - const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies = - std::vector<metadata::PositionalAccuracyNNPtr>()) { + const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies, + bool hasBallparkTransformation) { return util::nn_static_pointer_cast<SingleOperation>( PROJBasedOperation::create(properties, projExportable, false, sourceCRS, - targetCRS, accuracies)); + targetCRS, accuracies, + hasBallparkTransformation)); } //! @endcond @@ -2124,52 +2219,55 @@ void ParameterValue::_exportToWKT(io::WKTFormatter *formatter) const { const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; const auto &l_type = type(); - const auto &l_value = value(); - if (formatter->abridgedTransformation() && l_type == Type::MEASURE) { - const auto &unit = l_value.unit(); - const auto &unitType = unit.type(); - if (unitType == common::UnitOfMeasure::Type::LINEAR) { - formatter->add(l_value.getSIValue()); - } else if (unitType == common::UnitOfMeasure::Type::ANGULAR) { - formatter->add( - l_value.convertToUnit(common::UnitOfMeasure::ARC_SECOND)); - } else if (unit == common::UnitOfMeasure::PARTS_PER_MILLION) { - formatter->add(1.0 + l_value.value() * 1e-6); - } else { - formatter->add(l_value.value()); - } - } else if (l_type == Type::MEASURE) { - const auto &unit = l_value.unit(); - if (isWKT2) { - formatter->add(l_value.value()); - } else { - // In WKT1, as we don't output the natural unit, output to the - // registered linear / angular unit. + if (l_type == Type::MEASURE) { + const auto &l_value = value(); + if (formatter->abridgedTransformation()) { + const auto &unit = l_value.unit(); const auto &unitType = unit.type(); if (unitType == common::UnitOfMeasure::Type::LINEAR) { - const auto &targetUnit = *(formatter->axisLinearUnit()); - if (targetUnit.conversionToSI() == 0.0) { - throw io::FormattingException( - "cannot convert value to target linear unit"); - } - formatter->add(l_value.convertToUnit(targetUnit)); + formatter->add(l_value.getSIValue()); } else if (unitType == common::UnitOfMeasure::Type::ANGULAR) { - const auto &targetUnit = *(formatter->axisAngularUnit()); - if (targetUnit.conversionToSI() == 0.0) { - throw io::FormattingException( - "cannot convert value to target angular unit"); - } - formatter->add(l_value.convertToUnit(targetUnit)); + formatter->add( + l_value.convertToUnit(common::UnitOfMeasure::ARC_SECOND)); + } else if (unit == common::UnitOfMeasure::PARTS_PER_MILLION) { + formatter->add(1.0 + l_value.value() * 1e-6); } else { - formatter->add(l_value.getSIValue()); + formatter->add(l_value.value()); } - } - if (isWKT2 && unit != common::UnitOfMeasure::NONE) { - if (!formatter->primeMeridianOrParameterUnitOmittedIfSameAsAxis() || - (unit != common::UnitOfMeasure::SCALE_UNITY && - unit != *(formatter->axisLinearUnit()) && - unit != *(formatter->axisAngularUnit()))) { - unit._exportToWKT(formatter); + } else { + const auto &unit = l_value.unit(); + if (isWKT2) { + formatter->add(l_value.value()); + } else { + // In WKT1, as we don't output the natural unit, output to the + // registered linear / angular unit. + const auto &unitType = unit.type(); + if (unitType == common::UnitOfMeasure::Type::LINEAR) { + const auto &targetUnit = *(formatter->axisLinearUnit()); + if (targetUnit.conversionToSI() == 0.0) { + throw io::FormattingException( + "cannot convert value to target linear unit"); + } + formatter->add(l_value.convertToUnit(targetUnit)); + } else if (unitType == common::UnitOfMeasure::Type::ANGULAR) { + const auto &targetUnit = *(formatter->axisAngularUnit()); + if (targetUnit.conversionToSI() == 0.0) { + throw io::FormattingException( + "cannot convert value to target angular unit"); + } + formatter->add(l_value.convertToUnit(targetUnit)); + } else { + formatter->add(l_value.getSIValue()); + } + } + if (isWKT2 && unit != common::UnitOfMeasure::NONE) { + if (!formatter + ->primeMeridianOrParameterUnitOmittedIfSameAsAxis() || + (unit != common::UnitOfMeasure::SCALE_UNITY && + unit != *(formatter->axisLinearUnit()) && + unit != *(formatter->axisAngularUnit()))) { + unit._exportToWKT(formatter); + } } } } else if (l_type == Type::STRING || l_type == Type::FILENAME) { @@ -2256,6 +2354,10 @@ ConversionNNPtr Conversion::shallowClone() const { conv->setCRSs(this, false); return conv; } + +CoordinateOperationNNPtr Conversion::_shallowClone() const { + return util::nn_static_pointer_cast<CoordinateOperation>(shallowClone()); +} //! @endcond // --------------------------------------------------------------------------- @@ -4593,6 +4695,16 @@ InverseConversion::create(const ConversionNNPtr &forward) { return conv; } +// --------------------------------------------------------------------------- + +CoordinateOperationNNPtr InverseConversion::_shallowClone() const { + auto op = InverseConversion::nn_make_shared<InverseConversion>( + inverseAsConversion()->shallowClone()); + op->assignSelf(op); + op->setCRSs(this, false); + return util::nn_static_pointer_cast<CoordinateOperation>(op); +} + //! @endcond // --------------------------------------------------------------------------- @@ -4779,7 +4891,7 @@ ConversionPtr Conversion::convertToOtherMethod(int targetEPSGCode) const { common::Length( parameterValueMeasure(EPSG_CODE_PARAMETER_FALSE_NORTHING))); conv->setCRSs(this, false); - return std::move(conv); + return conv.as_nullable(); } if (current_epsg_code == EPSG_CODE_METHOD_MERCATOR_VARIANT_B && @@ -4800,7 +4912,7 @@ ConversionPtr Conversion::convertToOtherMethod(int targetEPSGCode) const { common::Length( parameterValueMeasure(EPSG_CODE_PARAMETER_FALSE_NORTHING))); conv->setCRSs(this, false); - return std::move(conv); + return conv.as_nullable(); } if (current_epsg_code == EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_1SP && @@ -4835,7 +4947,7 @@ ConversionPtr Conversion::convertToOtherMethod(int targetEPSGCode) const { common::Length( parameterValueMeasure(EPSG_CODE_PARAMETER_FALSE_NORTHING))); conv->setCRSs(this, false); - return std::move(conv); + return conv.as_nullable(); } else { const double K = k0 * m0 / std::pow(t0, n); const double phi1 = @@ -4891,7 +5003,7 @@ ConversionPtr Conversion::convertToOtherMethod(int targetEPSGCode) const { EPSG_CODE_PARAMETER_FALSE_EASTING)), common::Length(FN_corrected_rounded)); conv->setCRSs(this, false); - return std::move(conv); + return conv.as_nullable(); } } @@ -4905,7 +5017,7 @@ ConversionPtr Conversion::convertToOtherMethod(int targetEPSGCode) const { parameterValueMeasure(EPSG_CODE_PARAMETER_FALSE_EASTING)), common::Length(FN)); conv->setCRSs(this, false); - return std::move(conv); + return conv.as_nullable(); } } @@ -4969,7 +5081,7 @@ ConversionPtr Conversion::convertToOtherMethod(int targetEPSGCode) const { EPSG_CODE_PARAMETER_NORTHING_FALSE_ORIGIN) + (std::fabs(FN_correction) > 1e-8 ? FN_correction : 0))); conv->setCRSs(this, false); - return std::move(conv); + return conv.as_nullable(); } return nullptr; @@ -5008,10 +5120,11 @@ static void getESRIMethodNameAndParams(const Conversion *conv, } } else if (esriMapping->epsg_code == EPSG_CODE_METHOD_TRANSVERSE_MERCATOR) { - if (l_targetCRS && - (ci_find(l_targetCRS->nameStr(), "Gauss") != - std::string::npos || - ci_find(l_targetCRS->nameStr(), "GK_") != std::string::npos)) { + if (ci_find(conv->nameStr(), "Gauss Kruger") != std::string::npos || + (l_targetCRS && (ci_find(l_targetCRS->nameStr(), "Gauss") != + std::string::npos || + ci_find(l_targetCRS->nameStr(), "GK_") != + std::string::npos))) { esriParams = paramsESRI_Gauss_Kruger; esriMethodName = "Gauss_Kruger"; } else { @@ -5095,6 +5208,7 @@ const char *Conversion::getWKT1GDALMethodName() const { // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress + void Conversion::_exportToWKT(io::WKTFormatter *formatter) const { const auto &l_method = method(); const auto &methodName = l_method->nameStr(); @@ -5124,6 +5238,17 @@ void Conversion::_exportToWKT(io::WKTFormatter *formatter) const { formatter->pushOutputId(false); } +#ifdef DEBUG_CONVERSION_ID + if (sourceCRS() && targetCRS()) { + formatter->startNode("SOURCECRS_ID", false); + sourceCRS()->formatID(formatter); + formatter->endNode(); + formatter->startNode("TARGETCRS_ID", false); + targetCRS()->formatID(formatter); + formatter->endNode(); + } +#endif + bool bAlreadyWritten = false; if (!isWKT2 && formatter->useESRIDialect()) { const ESRIParamMapping *esriParams = nullptr; @@ -5644,7 +5769,9 @@ void Conversion::_exportToPROJString( common::UnitOfMeasure(std::string(), 1.0 / convFactor, common::UnitOfMeasure::Type::LINEAR) .exportToPROJString(); - if (!uom.empty()) { + if (uom == "m") { + // do nothing + } else if (!uom.empty()) { formatter->addStep("unitconvert"); formatter->addParam("z_in", uom); formatter->addParam("z_out", "m"); @@ -5948,10 +6075,14 @@ const crs::CRSNNPtr &Transformation::targetCRS() PROJ_PURE_DEFN { //! @cond Doxygen_Suppress TransformationNNPtr Transformation::shallowClone() const { - auto conv = Transformation::nn_make_shared<Transformation>(*this); - conv->assignSelf(conv); - conv->setCRSs(this, false); - return conv; + auto transf = Transformation::nn_make_shared<Transformation>(*this); + transf->assignSelf(transf); + transf->setCRSs(this, false); + return transf; +} + +CoordinateOperationNNPtr Transformation::_shallowClone() const { + return util::nn_static_pointer_cast<CoordinateOperation>(shallowClone()); } //! @endcond @@ -6136,12 +6267,17 @@ TransformationNNPtr Transformation::create( throw InvalidOperation( "Inconsistent number of parameters and parameter values"); } - auto conv = Transformation::nn_make_shared<Transformation>( + auto transf = Transformation::nn_make_shared<Transformation>( sourceCRSIn, targetCRSIn, interpolationCRSIn, methodIn, values, accuracies); - conv->assignSelf(conv); - conv->setProperties(properties); - return conv; + transf->assignSelf(transf); + transf->setProperties(properties); + std::string name; + if (properties.getStringValue(common::IdentifiedObject::NAME_KEY, name) && + ci_find(name, "ballpark") != std::string::npos) { + transf->setHasBallparkTransformation(true); + } + return transf; } // --------------------------------------------------------------------------- @@ -6822,11 +6958,11 @@ TransformationNNPtr Transformation::createNTv2( static TransformationNNPtr _createGravityRelatedHeightToGeographic3D( const util::PropertyMap &properties, bool inverse, const crs::CRSNNPtr &sourceCRSIn, const crs::CRSNNPtr &targetCRSIn, - const std::string &filename, + const crs::CRSPtr &interpolationCRSIn, const std::string &filename, const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies) { return Transformation::create( - properties, sourceCRSIn, targetCRSIn, nullptr, + properties, sourceCRSIn, targetCRSIn, interpolationCRSIn, util::PropertyMap().set( common::IdentifiedObject::NAME_KEY, inverse ? INVERSE_OF + PROJ_WKT2_NAME_METHOD_HEIGHT_TO_GEOG3D @@ -6845,17 +6981,20 @@ static TransformationNNPtr _createGravityRelatedHeightToGeographic3D( * At minimum the name should be defined. * @param sourceCRSIn Source CRS. * @param targetCRSIn Target CRS. + * @param interpolationCRSIn Interpolation CRS. (might be null) * @param filename GRID filename. * @param accuracies Vector of positional accuracy (might be empty). * @return new Transformation. */ TransformationNNPtr Transformation::createGravityRelatedHeightToGeographic3D( const util::PropertyMap &properties, const crs::CRSNNPtr &sourceCRSIn, - const crs::CRSNNPtr &targetCRSIn, const std::string &filename, + const crs::CRSNNPtr &targetCRSIn, const crs::CRSPtr &interpolationCRSIn, + const std::string &filename, const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies) { return _createGravityRelatedHeightToGeographic3D( - properties, false, sourceCRSIn, targetCRSIn, filename, accuracies); + properties, false, sourceCRSIn, targetCRSIn, interpolationCRSIn, + filename, accuracies); } // --------------------------------------------------------------------------- @@ -7054,6 +7193,39 @@ TransformationNNPtr Transformation::createVerticalOffset( // --------------------------------------------------------------------------- +/** \brief Instantiate a transformation based on the Change of Vertical Unit + * method. + * + * This method is defined as [EPSG:1069] + * (https://www.epsg-registry.org/export.htm?gml=urn:ogc:def:method:EPSG::1069) + * + * @param properties See \ref general_properties of the conversion. If the name + * is not provided, it is automatically set. + * @param sourceCRSIn Source CRS. + * @param targetCRSIn Target CRS. + * @param factor Conversion factor + * @param accuracies Vector of positional accuracy (might be empty). + * @return a new Transformation. + */ +TransformationNNPtr Transformation::createChangeVerticalUnit( + const util::PropertyMap &properties, const crs::CRSNNPtr &sourceCRSIn, + const crs::CRSNNPtr &targetCRSIn, const common::Scale &factor, + const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies) { + return create( + properties, sourceCRSIn, targetCRSIn, nullptr, + createMethodMapNameEPSGCode(EPSG_CODE_METHOD_CHANGE_VERTICAL_UNIT), + VectorOfParameters{ + createOpParamNameEPSGCode( + EPSG_CODE_PARAMETER_UNIT_CONVERSION_SCALAR), + }, + VectorOfValues{ + factor, + }, + accuracies); +} + +// --------------------------------------------------------------------------- + static const char *getCRSQualifierStr(const crs::CRSPtr &crs) { auto geod = dynamic_cast<crs::GeodeticCRS *>(crs.get()); if (geod) { @@ -7114,8 +7286,10 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom, // Forge a name for the inverse, either from the forward name, or // from the source and target CRS names const char *opType; - if (starts_with(forwardName, NULL_GEOCENTRIC_TRANSLATION)) { - opType = NULL_GEOCENTRIC_TRANSLATION; + if (starts_with(forwardName, BALLPARK_GEOCENTRIC_TRANSLATION)) { + opType = BALLPARK_GEOCENTRIC_TRANSLATION; + } else if (starts_with(forwardName, BALLPARK_GEOGRAPHIC_OFFSET)) { + opType = BALLPARK_GEOGRAPHIC_OFFSET; } else if (starts_with(forwardName, NULL_GEOGRAPHIC_OFFSET)) { opType = NULL_GEOGRAPHIC_OFFSET; } else if (dynamic_cast<const Transformation *>(op) || @@ -7131,8 +7305,20 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom, auto targetCRS = op->targetCRS(); std::string name; if (!forwardName.empty()) { - if (starts_with(forwardName, INVERSE_OF)) { - name = forwardName.substr(INVERSE_OF.size()); + if (starts_with(forwardName, INVERSE_OF) || + forwardName.find(" + ") != std::string::npos) { + auto tokens = split(forwardName, " + "); + for (size_t i = tokens.size(); i > 0;) { + i--; + if (!name.empty()) { + name += " + "; + } + if (starts_with(tokens[i], INVERSE_OF)) { + name += tokens[i].substr(INVERSE_OF.size()); + } else { + name += INVERSE_OF + tokens[i]; + } + } } else if (!sourceCRS || !targetCRS || forwardName != buildOpName(opType, sourceCRS, targetCRS)) { name = INVERSE_OF + forwardName; @@ -7314,6 +7500,8 @@ Transformation::Private::registerInv(util::BaseObjectNNPtr thisIn, TransformationNNPtr invTransform) { invTransform->d->forwardOperation_ = util::nn_dynamic_pointer_cast<Transformation>(thisIn); + invTransform->setHasBallparkTransformation( + invTransform->d->forwardOperation_->hasBallparkTransformation()); return invTransform; } //! @endcond @@ -7481,6 +7669,17 @@ TransformationNNPtr Transformation::inverseAsTransformation() const { coordinateOperationAccuracies())); } + if (methodEPSGCode == EPSG_CODE_METHOD_CHANGE_VERTICAL_UNIT) { + const double convFactor = parameterValueNumericAsSI( + EPSG_CODE_PARAMETER_UNIT_CONVERSION_SCALAR); + return d->registerInv( + shared_from_this(), + createChangeVerticalUnit( + createPropertiesForInverse(this, false, false), l_targetCRS, + l_sourceCRS, common::Scale(1.0 / convFactor), + coordinateOperationAccuracies())); + } + return InverseTransformation::create(NN_NO_CHECK( util::nn_dynamic_pointer_cast<Transformation>(shared_from_this()))); } @@ -7517,6 +7716,13 @@ InverseTransformation::create(const TransformationNNPtr &forward) { // --------------------------------------------------------------------------- +TransformationNNPtr InverseTransformation::inverseAsTransformation() const { + return NN_NO_CHECK( + util::nn_dynamic_pointer_cast<Transformation>(forwardOperation_)); +} + +// --------------------------------------------------------------------------- + void InverseTransformation::_exportToWKT(io::WKTFormatter *formatter) const { auto approxInverse = createApproximateInverseIfPossible( @@ -7528,6 +7734,16 @@ void InverseTransformation::_exportToWKT(io::WKTFormatter *formatter) const { } } +// --------------------------------------------------------------------------- + +CoordinateOperationNNPtr InverseTransformation::_shallowClone() const { + auto op = InverseTransformation::nn_make_shared<InverseTransformation>( + inverseAsTransformation()->shallowClone()); + op->assignSelf(op); + op->setCRSs(this, false); + return util::nn_static_pointer_cast<CoordinateOperation>(op); +} + //! @endcond // --------------------------------------------------------------------------- @@ -7540,6 +7756,53 @@ void Transformation::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +static void exportSourceCRSAndTargetCRSToWKT(const CoordinateOperation *co, + io::WKTFormatter *formatter) { + auto l_sourceCRS = co->sourceCRS(); + assert(l_sourceCRS); + auto l_targetCRS = co->targetCRS(); + assert(l_targetCRS); + const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; + const bool canExportCRSId = + (isWKT2 && formatter->use2018Keywords() && + !(formatter->idOnTopLevelOnly() && formatter->topLevelHasId())); + + const bool hasDomains = !co->domains().empty(); + if (hasDomains) { + formatter->pushDisableUsage(); + } + + formatter->startNode(io::WKTConstants::SOURCECRS, false); + if (canExportCRSId && !l_sourceCRS->identifiers().empty()) { + // fake that top node has no id, so that the sourceCRS id is + // considered + formatter->pushHasId(false); + l_sourceCRS->_exportToWKT(formatter); + formatter->popHasId(); + } else { + l_sourceCRS->_exportToWKT(formatter); + } + formatter->endNode(); + + formatter->startNode(io::WKTConstants::TARGETCRS, false); + if (canExportCRSId && !l_targetCRS->identifiers().empty()) { + // fake that top node has no id, so that the targetCRS id is + // considered + formatter->pushHasId(false); + l_targetCRS->_exportToWKT(formatter); + formatter->popHasId(); + } else { + l_targetCRS->_exportToWKT(formatter); + } + formatter->endNode(); + + if (hasDomains) { + formatter->popDisableUsage(); + } +} + +// --------------------------------------------------------------------------- + void SingleOperation::exportTransformationToWKT( io::WKTFormatter *formatter) const { const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; @@ -7548,11 +7811,6 @@ void SingleOperation::exportTransformationToWKT( "Transformation can only be exported to WKT2"); } - auto l_sourceCRS = sourceCRS(); - assert(l_sourceCRS); - auto l_targetCRS = targetCRS(); - assert(l_targetCRS); - if (formatter->abridgedTransformation()) { formatter->startNode(io::WKTConstants::ABRIDGEDTRANSFORMATION, !identifiers().empty()); @@ -7563,22 +7821,23 @@ void SingleOperation::exportTransformationToWKT( formatter->addQuotedString(nameStr()); - if (!formatter->abridgedTransformation()) { - formatter->startNode(io::WKTConstants::SOURCECRS, false); - l_sourceCRS->_exportToWKT(formatter); - formatter->endNode(); + if (formatter->use2018Keywords()) { + const auto &version = operationVersion(); + if (version.has_value()) { + formatter->startNode(io::WKTConstants::VERSION, false); + formatter->addQuotedString(*version); + formatter->endNode(); + } + } - formatter->startNode(io::WKTConstants::TARGETCRS, false); - l_targetCRS->_exportToWKT(formatter); - formatter->endNode(); + if (!formatter->abridgedTransformation()) { + exportSourceCRSAndTargetCRSToWKT(this, formatter); } method()->_exportToWKT(formatter); - const MethodMapping *mapping = - !isWKT2 ? getMapping(method().get()) : nullptr; for (const auto ¶mValue : parameterValues()) { - paramValue->_exportToWKT(formatter, mapping); + paramValue->_exportToWKT(formatter, nullptr); } if (!formatter->abridgedTransformation()) { @@ -7951,13 +8210,14 @@ TransformationNNPtr Transformation::substitutePROJAlternativeGridNames( return createGravityRelatedHeightToGeographic3D( createPropertiesForInverse(self.as_nullable().get(), true, false), - targetCRS(), sourceCRS(), projFilename, - coordinateOperationAccuracies()) + targetCRS(), sourceCRS(), interpolationCRS(), + projFilename, coordinateOperationAccuracies()) ->inverseAsTransformation(); } else { return createGravityRelatedHeightToGeographic3D( createSimilarPropertiesTransformation(self), sourceCRS(), - targetCRS(), projFilename, coordinateOperationAccuracies()); + targetCRS(), interpolationCRS(), projFilename, + coordinateOperationAccuracies()); } } } @@ -8001,6 +8261,46 @@ TransformationNNPtr Transformation::substitutePROJAlternativeGridNames( } } + if (methodEPSGCode == EPSG_CODE_METHOD_VERTCON) { + auto fileParameter = + parameterValue(EPSG_NAME_PARAMETER_VERTICAL_OFFSET_FILE, + EPSG_CODE_PARAMETER_VERTICAL_OFFSET_FILE); + if (fileParameter && + fileParameter->type() == ParameterValue::Type::FILENAME) { + + auto filename = fileParameter->valueFile(); + if (databaseContext->lookForGridAlternative( + filename, projFilename, projGridFormat, inverseDirection)) { + + if (filename == projFilename) { + assert(!inverseDirection); + return self; + } + + auto parameters = std::vector<OperationParameterNNPtr>{ + createOpParamNameEPSGCode( + EPSG_CODE_PARAMETER_VERTICAL_OFFSET_FILE)}; + if (inverseDirection) { + return create(createPropertiesForInverse( + self.as_nullable().get(), true, false), + targetCRS(), sourceCRS(), nullptr, + createSimilarPropertiesMethod(method()), + parameters, {ParameterValue::createFilename( + projFilename)}, + coordinateOperationAccuracies()) + ->inverseAsTransformation(); + } else { + return create( + createSimilarPropertiesTransformation(self), + sourceCRS(), targetCRS(), nullptr, + createSimilarPropertiesMethod(method()), parameters, + {ParameterValue::createFilename(projFilename)}, + coordinateOperationAccuracies()); + } + } + } + } + return self; } // --------------------------------------------------------------------------- @@ -8016,7 +8316,7 @@ static void ThrowExceptionNotGeodeticGeographic(const char *trfrm_name) { // --------------------------------------------------------------------------- static void setupPROJGeodeticSourceCRS(io::PROJStringFormatter *formatter, - const crs::CRSNNPtr &crs, + const crs::CRSNNPtr &crs, bool addPushV3, const char *trfrm_name) { auto sourceCRSGeog = dynamic_cast<const crs::GeographicCRS *>(crs.get()); if (sourceCRSGeog) { @@ -8024,6 +8324,11 @@ static void setupPROJGeodeticSourceCRS(io::PROJStringFormatter *formatter, sourceCRSGeog->_exportToPROJString(formatter); formatter->stopInversion(); + if (addPushV3) { + formatter->addStep("push"); + formatter->addParam("v_3"); + } + formatter->addStep("cart"); sourceCRSGeog->ellipsoid()->_exportToPROJString(formatter); } else { @@ -8039,7 +8344,7 @@ static void setupPROJGeodeticSourceCRS(io::PROJStringFormatter *formatter, // --------------------------------------------------------------------------- static void setupPROJGeodeticTargetCRS(io::PROJStringFormatter *formatter, - const crs::CRSNNPtr &crs, + const crs::CRSNNPtr &crs, bool addPopV3, const char *trfrm_name) { auto targetCRSGeog = dynamic_cast<const crs::GeographicCRS *>(crs.get()); if (targetCRSGeog) { @@ -8047,6 +8352,11 @@ static void setupPROJGeodeticTargetCRS(io::PROJStringFormatter *formatter, formatter->setCurrentStepInverted(true); targetCRSGeog->ellipsoid()->_exportToPROJString(formatter); + if (addPopV3) { + formatter->addStep("pop"); + formatter->addParam("v_3"); + } + targetCRSGeog->_exportToPROJString(formatter); } else { auto targetCRSGeod = dynamic_cast<const crs::GeodeticCRS *>(crs.get()); @@ -8138,19 +8448,19 @@ void Transformation::_exportToPROJString( double z = parameterValueNumericAsSI(EPSG_CODE_PARAMETER_Z_AXIS_TRANSLATION); - if (methodEPSGCode == EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_2D || - methodEPSGCode == - EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_2D || - methodEPSGCode == EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_2D || - methodEPSGCode == - EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_2D || - methodEPSGCode == - EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_2D) { - formatter->addStep("push"); - formatter->addParam("v_3"); - } + bool addPushPopV3 = + (methodEPSGCode == + EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_2D || + methodEPSGCode == + EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_2D || + methodEPSGCode == EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_2D || + methodEPSGCode == + EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_2D || + methodEPSGCode == + EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_2D); - setupPROJGeodeticSourceCRS(formatter, sourceCRS(), "Helmert"); + setupPROJGeodeticSourceCRS(formatter, sourceCRS(), addPushPopV3, + "Helmert"); formatter->addStep("helmert"); formatter->addParam("x", x); @@ -8214,19 +8524,8 @@ void Transformation::_exportToPROJString( } } - setupPROJGeodeticTargetCRS(formatter, targetCRS(), "Helmert"); - - if (methodEPSGCode == EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_2D || - methodEPSGCode == - EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_2D || - methodEPSGCode == EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_2D || - methodEPSGCode == - EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_2D || - methodEPSGCode == - EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_2D) { - formatter->addStep("pop"); - formatter->addParam("v_3"); - } + setupPROJGeodeticTargetCRS(formatter, targetCRS(), addPushPopV3, + "Helmert"); return; } @@ -8274,15 +8573,13 @@ void Transformation::_exportToPROJString( double pz = parameterValueNumericAsSI( EPSG_CODE_PARAMETER_ORDINATE_3_EVAL_POINT); - if (methodEPSGCode == - EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_2D || - methodEPSGCode == - EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_2D) { - formatter->addStep("push"); - formatter->addParam("v_3"); - } + bool addPushPopV3 = + (methodEPSGCode == + EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_2D || + methodEPSGCode == + EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_2D); - setupPROJGeodeticSourceCRS(formatter, sourceCRS(), + setupPROJGeodeticSourceCRS(formatter, sourceCRS(), addPushPopV3, "Molodensky-Badekas"); formatter->addStep("molobadekas"); @@ -8302,17 +8599,9 @@ void Transformation::_exportToPROJString( formatter->addParam("convention", "coordinate_frame"); } - setupPROJGeodeticTargetCRS(formatter, targetCRS(), + setupPROJGeodeticTargetCRS(formatter, targetCRS(), addPushPopV3, "Molodensky-Badekas"); - if (methodEPSGCode == - EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_PV_GEOGRAPHIC_2D || - methodEPSGCode == - EPSG_CODE_METHOD_MOLODENSKY_BADEKAS_CF_GEOGRAPHIC_2D) { - formatter->addStep("pop"); - formatter->addParam("v_3"); - } - return; } @@ -8605,13 +8894,25 @@ void Transformation::_exportToPROJString( if (fileParameter && fileParameter->type() == ParameterValue::Type::FILENAME) { auto filename = fileParameter->valueFile(); - if (isMethodInverseOf) { + bool doInversion = isMethodInverseOf; + if (!identifiers().empty() && + *identifiers().front()->codeSpace() == + metadata::Identifier::EPSG && + method()->nameStr() == + "Geographic3D to GravityRelatedHeight (US .gtx)" && + ends_with(filename, ".gtx")) { + // gtx files, from straight EPSG definition, must be applied in + // reverse order for "Geographic3D to GravityRelatedHeight" + // method + doInversion = !doInversion; + } + if (doInversion) { formatter->startInversion(); } formatter->addStep("vgridshift"); formatter->addParam("grids", filename); formatter->addParam("multiplier", 1.0); - if (isMethodInverseOf) { + if (doInversion) { formatter->stopInversion(); } return; @@ -8795,6 +9096,33 @@ bool SingleOperation::exportToPROJStringGeneric( "conversion"); } + if (methodEPSGCode == EPSG_CODE_METHOD_CHANGE_VERTICAL_UNIT) { + double convFactor = parameterValueNumericAsSI( + EPSG_CODE_PARAMETER_UNIT_CONVERSION_SCALAR); + auto uom = common::UnitOfMeasure(std::string(), convFactor, + common::UnitOfMeasure::Type::LINEAR) + .exportToPROJString(); + auto reverse_uom = + common::UnitOfMeasure(std::string(), 1.0 / convFactor, + common::UnitOfMeasure::Type::LINEAR) + .exportToPROJString(); + if (uom == "m") { + // do nothing + } else if (!uom.empty()) { + formatter->addStep("unitconvert"); + formatter->addParam("z_in", uom); + formatter->addParam("z_out", "m"); + } else if (!reverse_uom.empty()) { + formatter->addStep("unitconvert"); + formatter->addParam("z_in", "m"); + formatter->addParam("z_out", reverse_uom); + } else { + formatter->addStep("affine"); + formatter->addParam("s33", convFactor); + } + return true; + } + return false; } @@ -8813,6 +9141,7 @@ struct ConcatenatedOperation::Private { explicit Private(const std::vector<CoordinateOperationNNPtr> &operationsIn) : operations_(operationsIn) {} + Private(const Private &) = default; }; //! @endcond @@ -8824,6 +9153,14 @@ ConcatenatedOperation::~ConcatenatedOperation() = default; // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +ConcatenatedOperation::ConcatenatedOperation(const ConcatenatedOperation &other) + : CoordinateOperation(other), + d(internal::make_unique<Private>(*(other.d))) {} +//! @endcond + +// --------------------------------------------------------------------------- + ConcatenatedOperation::ConcatenatedOperation( const std::vector<CoordinateOperationNNPtr> &operationsIn) : CoordinateOperation(), d(internal::make_unique<Private>(operationsIn)) {} @@ -8886,6 +9223,22 @@ ConcatenatedOperationNNPtr ConcatenatedOperation::create( } if (i >= 1) { if (!compareStepCRS(l_sourceCRS.get(), lastTargetCRS.get())) { +#ifdef DEBUG_CONCATENATED_OPERATION + { + auto f(io::WKTFormatter::create( + io::WKTFormatter::Convention::WKT2_2018)); + std::cerr << "Source CRS of step " << i << ":" << std::endl; + std::cerr << l_sourceCRS->exportToWKT(f.get()) << std::endl; + } + { + auto f(io::WKTFormatter::create( + io::WKTFormatter::Convention::WKT2_2018)); + std::cerr << "Target CRS of step " << i - 1 << ":" + << std::endl; + std::cerr << lastTargetCRS->exportToWKT(f.get()) + << std::endl; + } +#endif throw InvalidOperation( "Inconsistent chaining of CRS in operations"); } @@ -8899,6 +9252,14 @@ ConcatenatedOperationNNPtr ConcatenatedOperation::create( op->setCRSs(NN_NO_CHECK(operationsIn[0]->sourceCRS()), NN_NO_CHECK(operationsIn.back()->targetCRS()), nullptr); op->setAccuracies(accuracies); +#ifdef DEBUG_CONCATENATED_OPERATION + { + auto f( + io::WKTFormatter::create(io::WKTFormatter::Convention::WKT2_2018)); + std::cerr << "ConcatenatedOperation::create()" << std::endl; + std::cerr << op->exportToWKT(f.get()) << std::endl; + } +#endif return op; } @@ -8951,6 +9312,7 @@ void ConcatenatedOperation::fixStepsDirection( op = op->inverse(); } } else if (i + 1 < operationsInOut.size()) { + /* coverity[copy_paste_error] */ l_targetCRS = operationsInOut[i + 1]->sourceCRS(); if (l_targetCRS) { op->setCRSs(concatOpSourceCRS, NN_NO_CHECK(l_targetCRS), @@ -9080,7 +9442,9 @@ CoordinateOperationNNPtr ConcatenatedOperation::createComputeMetadata( } std::vector<CoordinateOperationNNPtr> flattenOps; + bool hasBallparkTransformation = false; for (const auto &subOp : operationsIn) { + hasBallparkTransformation |= subOp->hasBallparkTransformation(); auto subOpConcat = dynamic_cast<const ConcatenatedOperation *>(subOp.get()); if (subOpConcat) { @@ -9120,6 +9484,7 @@ CoordinateOperationNNPtr ConcatenatedOperation::createComputeMetadata( } auto op = create(properties, flattenOps, accuracies); + op->setHasBallparkTransformation(hasBallparkTransformation); op->d->computedName_ = true; return op; } @@ -9144,6 +9509,7 @@ CoordinateOperationNNPtr ConcatenatedOperation::inverse() const { auto op = create(properties, inversedOperations, coordinateOperationAccuracies()); op->d->computedName_ = d->computedName_; + op->setHasBallparkTransformation(hasBallparkTransformation()); return op; } @@ -9161,20 +9527,43 @@ void ConcatenatedOperation::_exportToWKT(io::WKTFormatter *formatter) const { !identifiers().empty()); formatter->addQuotedString(nameStr()); - formatter->startNode(io::WKTConstants::SOURCECRS, false); - sourceCRS()->_exportToWKT(formatter); - formatter->endNode(); + if (isWKT2 && formatter->use2018Keywords()) { + const auto &version = operationVersion(); + if (version.has_value()) { + formatter->startNode(io::WKTConstants::VERSION, false); + formatter->addQuotedString(*version); + formatter->endNode(); + } + } - formatter->startNode(io::WKTConstants::TARGETCRS, false); - targetCRS()->_exportToWKT(formatter); - formatter->endNode(); + exportSourceCRSAndTargetCRSToWKT(this, formatter); + + const bool canExportOperationId = + !(formatter->idOnTopLevelOnly() && formatter->topLevelHasId()); + + const bool hasDomains = !domains().empty(); + if (hasDomains) { + formatter->pushDisableUsage(); + } for (const auto &operation : operations()) { formatter->startNode(io::WKTConstants::STEP, false); - operation->_exportToWKT(formatter); + if (canExportOperationId && !operation->identifiers().empty()) { + // fake that top node has no id, so that the operation id is + // considered + formatter->pushHasId(false); + operation->_exportToWKT(formatter); + formatter->popHasId(); + } else { + operation->_exportToWKT(formatter); + } formatter->endNode(); } + if (hasDomains) { + formatter->popDisableUsage(); + } + ObjectUsage::baseExportToWKT(formatter); formatter->endNode(); } @@ -9182,6 +9571,18 @@ void ConcatenatedOperation::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +CoordinateOperationNNPtr ConcatenatedOperation::_shallowClone() const { + auto op = + ConcatenatedOperation::nn_make_shared<ConcatenatedOperation>(*this); + op->assignSelf(op); + op->setCRSs(this, false); + return util::nn_static_pointer_cast<CoordinateOperation>(op); +} +//! @endcond + +// --------------------------------------------------------------------------- + void ConcatenatedOperation::_exportToPROJString( io::PROJStringFormatter *formatter) const // throw(FormattingException) { @@ -9627,14 +10028,18 @@ struct PrecomputedOpCharacteristics { bool gridsAvailable_ = false; bool gridsKnown_ = false; size_t stepCount_ = 0; + bool isApprox_ = false; + bool isNullTransformation_ = false; PrecomputedOpCharacteristics() = default; PrecomputedOpCharacteristics(double area, double accuracy, bool hasGrids, bool gridsAvailable, bool gridsKnown, - size_t stepCount) + size_t stepCount, bool isApprox, + bool isNullTransformation) : area_(area), accuracy_(accuracy), hasGrids_(hasGrids), gridsAvailable_(gridsAvailable), gridsKnown_(gridsKnown), - stepCount_(stepCount) {} + stepCount_(stepCount), isApprox_(isApprox), + isNullTransformation_(isNullTransformation) {} }; // --------------------------------------------------------------------------- @@ -9661,6 +10066,22 @@ struct SortFunction { // CAUTION: the order of the comparisons is extremely important // to get the intended result. + if (!iterA->second.isApprox_ && iterB->second.isApprox_) { + return true; + } + if (iterA->second.isApprox_ && !iterB->second.isApprox_) { + return false; + } + + if (!iterA->second.isNullTransformation_ && + iterB->second.isNullTransformation_) { + return true; + } + if (iterA->second.isNullTransformation_ && + !iterB->second.isNullTransformation_) { + return false; + } + if (iterA->second.hasGrids_ && iterB->second.hasGrids_) { // Operations where grids are all available go before other if (iterA->second.gridsAvailable_ && @@ -9691,6 +10112,17 @@ struct SortFunction { return false; } + if (accuracyA < 0 && accuracyB < 0) { + // unknown accuracy ? then prefer operations with grids, which + // are likely to have best practical accuracy + if (iterA->second.hasGrids_ && !iterB->second.hasGrids_) { + return true; + } + if (!iterA->second.hasGrids_ && iterB->second.hasGrids_) { + return false; + } + } + // Operations with larger non-zero area of use go before those with // lower one const double areaA = iterA->second.area_; @@ -9722,15 +10154,6 @@ struct SortFunction { if (iterA->second.hasGrids_ && !iterB->second.hasGrids_) { return false; } - } else if (accuracyA < 0 && accuracyB < 0) { - // unknown accuracy ? then prefer operations with grids, which - // are likely to have best practical accuracy - if (iterA->second.hasGrids_ && !iterB->second.hasGrids_) { - return true; - } - if (!iterA->second.hasGrids_ && iterB->second.hasGrids_) { - return false; - } } // The less intermediate steps, the better @@ -9882,11 +10305,7 @@ struct FilterResults { bool extentContains = extent->contains(NN_NO_CHECK(areaOfInterest)); if (extentContains) { - const auto &name = op->nameStr(); - if (name.find(NULL_GEOGRAPHIC_OFFSET) == - std::string::npos && - name.find(NULL_GEOCENTRIC_TRANSLATION) == - std::string::npos) { + if (!op->hasBallparkTransformation()) { hasOpThatContainsAreaOfInterest = true; } } @@ -9917,11 +10336,7 @@ struct FilterResults { !targetCRSExtent || extent->contains(NN_NO_CHECK(targetCRSExtent)); if (extentContainsSource && extentContainsTarget) { - const auto &name = op->nameStr(); - if (name.find(NULL_GEOGRAPHIC_OFFSET) == - std::string::npos && - name.find(NULL_GEOCENTRIC_TRANSLATION) == - std::string::npos) { + if (!op->hasBallparkTransformation()) { hasOpThatContainsAreaOfInterest = true; } } @@ -10002,13 +10417,7 @@ struct FilterResults { bool hasGrids = false; bool gridsAvailable = true; bool gridsKnown = true; - if (context->getAuthorityFactory() && - (gridAvailabilityUse == - CoordinateOperationContext::GridAvailabilityUse:: - USE_FOR_SORTING || - gridAvailabilityUse == - CoordinateOperationContext::GridAvailabilityUse:: - IGNORE_GRID_AVAILABILITY)) { + if (context->getAuthorityFactory()) { const auto gridsNeeded = op->gridsNeeded( context->getAuthorityFactory()->databaseContext()); for (const auto &gridDesc : gridsNeeded) { @@ -10027,9 +10436,19 @@ struct FilterResults { const auto stepCount = getStepCount(op); + const bool isApprox = + op->nameStr().find(BALLPARK_VERTICAL_TRANSFORMATION_PREFIX) != + std::string::npos; + const bool isNullTransformation = + op->nameStr().find(BALLPARK_GEOGRAPHIC_OFFSET) != + std::string::npos || + op->nameStr().find(NULL_GEOGRAPHIC_OFFSET) != + std::string::npos || + op->nameStr().find(BALLPARK_GEOCENTRIC_TRANSLATION) != + std::string::npos; map[op.get()] = PrecomputedOpCharacteristics( area, getAccuracy(op), hasGrids, gridsAvailable, gridsKnown, - stepCount); + stepCount, isApprox, isNullTransformation); } // Sort ! @@ -10041,13 +10460,17 @@ struct FilterResults { void removeSyntheticNullTransforms() { // If we have more than one result, and than the last result is the - // default "Null geographic offset" or "Null geocentric translation" - // operations we have synthetized, remove it as + // default "Ballpark geographic offset" or "Ballpark geocentric + // translation" + // operations we have synthetized, and that at least one operation + // has the desired area of interest, remove it as // all previous results are necessarily better if (hasOpThatContainsAreaOfInterest && res.size() > 1) { const std::string &name = res.back()->nameStr(); - if (name.find(NULL_GEOGRAPHIC_OFFSET) != std::string::npos || - name.find(NULL_GEOCENTRIC_TRANSLATION) != std::string::npos) { + if (name.find(BALLPARK_GEOGRAPHIC_OFFSET) != std::string::npos || + name.find(NULL_GEOGRAPHIC_OFFSET) != std::string::npos || + name.find(BALLPARK_GEOCENTRIC_TRANSLATION) != + std::string::npos) { std::vector<CoordinateOperationNNPtr> resTemp; for (size_t i = 0; i < res.size() - 1; i++) { resTemp.emplace_back(res[i]); @@ -10460,9 +10883,20 @@ static std::vector<CoordinateOperationNNPtr> findsOpsInRegistryWithIntermediate( //! @cond Doxygen_Suppress static TransformationNNPtr -createNullGeographicOffset(const crs::CRSNNPtr &sourceCRS, - const crs::CRSNNPtr &targetCRS) { - std::string name(NULL_GEOGRAPHIC_OFFSET); +createBallparkGeographicOffset(const crs::CRSNNPtr &sourceCRS, + const crs::CRSNNPtr &targetCRS) { + + const crs::GeographicCRS *geogSrc = + dynamic_cast<const crs::GeographicCRS *>(sourceCRS.get()); + const crs::GeographicCRS *geogDst = + dynamic_cast<const crs::GeographicCRS *>(targetCRS.get()); + const bool isSameDatum = + geogSrc && geogDst && geogSrc->datum() && geogDst->datum() && + geogSrc->datum()->_isEquivalentTo( + geogDst->datum().get(), util::IComparable::Criterion::EQUIVALENT); + + std::string name(isSameDatum ? NULL_GEOGRAPHIC_OFFSET + : BALLPARK_GEOGRAPHIC_OFFSET); name += " from "; name += sourceCRS->nameStr(); name += " to "; @@ -10481,6 +10915,12 @@ createNullGeographicOffset(const crs::CRSNNPtr &sourceCRS, sameExtent ? NN_NO_CHECK(sourceCRSExtent) : metadata::Extent::WORLD); const common::Angle angle0(0); + + std::vector<metadata::PositionalAccuracyNNPtr> accuracies; + if (isSameDatum) { + accuracies.emplace_back(metadata::PositionalAccuracy::create("0")); + } + if (dynamic_cast<const crs::SingleCRS *>(sourceCRS.get()) ->coordinateSystem() ->axisList() @@ -10490,10 +10930,11 @@ createNullGeographicOffset(const crs::CRSNNPtr &sourceCRS, ->axisList() .size() == 3) { return Transformation::createGeographic3DOffsets( - map, sourceCRS, targetCRS, angle0, angle0, common::Length(0), {}); + map, sourceCRS, targetCRS, angle0, angle0, common::Length(0), + accuracies); } else { return Transformation::createGeographic2DOffsets( - map, sourceCRS, targetCRS, angle0, angle0, {}); + map, sourceCRS, targetCRS, angle0, angle0, accuracies); } } //! @endcond @@ -10547,19 +10988,19 @@ struct MyPROJStringExportableHorizVertical final // cppcheck-suppress functionStatic _exportToPROJString(io::PROJStringFormatter *formatter) const override { - formatter->setOmitZUnitConversion(true); + formatter->pushOmitZUnitConversion(); horizTransform->_exportToPROJString(formatter); formatter->startInversion(); geogDst->addAngularUnitConvertAndAxisSwap(formatter); formatter->stopInversion(); - formatter->setOmitZUnitConversion(false); + formatter->popOmitZUnitConversion(); verticalTransform->_exportToPROJString(formatter); - formatter->setOmitZUnitConversion(true); + formatter->pushOmitZUnitConversion(); geogDst->addAngularUnitConvertAndAxisSwap(formatter); - formatter->setOmitZUnitConversion(false); + formatter->popOmitZUnitConversion(); } }; @@ -10591,7 +11032,7 @@ struct MyPROJStringExportableHorizVerticalHorizPROJBased final // cppcheck-suppress functionStatic _exportToPROJString(io::PROJStringFormatter *formatter) const override { - formatter->setOmitZUnitConversion(true); + formatter->pushOmitZUnitConversion(); opSrcCRSToGeogCRS->_exportToPROJString(formatter); @@ -10599,23 +11040,23 @@ struct MyPROJStringExportableHorizVerticalHorizPROJBased final interpolationGeogCRS->addAngularUnitConvertAndAxisSwap(formatter); formatter->stopInversion(); - formatter->setOmitZUnitConversion(false); + formatter->popOmitZUnitConversion(); verticalTransform->_exportToPROJString(formatter); - formatter->setOmitZUnitConversion(true); + formatter->pushOmitZUnitConversion(); interpolationGeogCRS->addAngularUnitConvertAndAxisSwap(formatter); opGeogCRStoDstCRS->_exportToPROJString(formatter); - formatter->setOmitZUnitConversion(false); + formatter->popOmitZUnitConversion(); } }; MyPROJStringExportableHorizVerticalHorizPROJBased:: ~MyPROJStringExportableHorizVerticalHorizPROJBased() = default; -} +} // namespace operation NS_PROJ_END #if 0 @@ -10653,7 +11094,7 @@ createGeodToGeodPROJBased(const crs::CRSNNPtr &geodSrc, auto properties = util::PropertyMap().set( common::IdentifiedObject::NAME_KEY, buildTransfName(geodSrc->nameStr(), geodDst->nameStr())); - return createPROJBased(properties, exportable, geodSrc, geodDst); + return createPROJBased(properties, exportable, geodSrc, geodDst, {}, false); } // --------------------------------------------------------------------------- @@ -10669,28 +11110,58 @@ static CoordinateOperationNNPtr createHorizVerticalPROJBased( auto exportable = util::nn_make_shared<MyPROJStringExportableHorizVertical>( horizTransform, verticalTransform, geogDst); - bool dummy = false; - auto ops = std::vector<CoordinateOperationNNPtr>{horizTransform, - verticalTransform}; - auto extent = getExtent(ops, true, dummy); - auto properties = util::PropertyMap(); - properties.set(common::IdentifiedObject::NAME_KEY, - computeConcatenatedName(ops)); - - if (extent) { - properties.set(common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, - NN_NO_CHECK(extent)); + bool horizTransformIsNoOp = horizTransform->sourceCRS()->_isEquivalentTo( + horizTransform->targetCRS().get()); + if (!horizTransformIsNoOp) { + const crs::GeographicCRS *geogSrc = + dynamic_cast<const crs::GeographicCRS *>( + horizTransform->sourceCRS().get()); + if (geogSrc) { + horizTransformIsNoOp = + geogSrc->is2DPartOf3D(NN_NO_CHECK(geogDst.get())); + } } - std::vector<metadata::PositionalAccuracyNNPtr> accuracies; - const double accuracy = getAccuracy(ops); - if (accuracy >= 0.0) { - accuracies.emplace_back( - metadata::PositionalAccuracy::create(toString(accuracy))); - } + if (horizTransformIsNoOp) { + auto properties = util::PropertyMap(); + properties.set(common::IdentifiedObject::NAME_KEY, + verticalTransform->nameStr()); + bool dummy = false; + auto extent = getExtent(verticalTransform, true, dummy); + if (extent) { + properties.set(common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, + NN_NO_CHECK(extent)); + } + return createPROJBased( + properties, exportable, sourceCRS, targetCRS, + verticalTransform->coordinateOperationAccuracies(), + verticalTransform->hasBallparkTransformation()); + } else { + bool dummy = false; + auto ops = std::vector<CoordinateOperationNNPtr>{horizTransform, + verticalTransform}; + auto extent = getExtent(ops, true, dummy); + auto properties = util::PropertyMap(); + properties.set(common::IdentifiedObject::NAME_KEY, + computeConcatenatedName(ops)); - return createPROJBased(properties, exportable, sourceCRS, targetCRS, - accuracies); + if (extent) { + properties.set(common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, + NN_NO_CHECK(extent)); + } + + std::vector<metadata::PositionalAccuracyNNPtr> accuracies; + const double accuracy = getAccuracy(ops); + if (accuracy >= 0.0) { + accuracies.emplace_back( + metadata::PositionalAccuracy::create(toString(accuracy))); + } + + return createPROJBased( + properties, exportable, sourceCRS, targetCRS, accuracies, + horizTransform->hasBallparkTransformation() || + verticalTransform->hasBallparkTransformation()); + } } // --------------------------------------------------------------------------- @@ -10708,8 +11179,17 @@ static CoordinateOperationNNPtr createHorizVerticalHorizPROJBased( interpolationGeogCRS); bool dummy = false; - auto ops = std::vector<CoordinateOperationNNPtr>{ - opSrcCRSToGeogCRS, verticalTransform, opGeogCRStoDstCRS}; + auto ops = opSrcCRSToGeogCRS->sourceCRS()->_isEquivalentTo( + opSrcCRSToGeogCRS->targetCRS().get()) + ? std::vector<CoordinateOperationNNPtr>{verticalTransform, + opGeogCRStoDstCRS} + : std::vector<CoordinateOperationNNPtr>{opSrcCRSToGeogCRS, + verticalTransform, + opGeogCRStoDstCRS}; + bool hasBallparkTransformation = false; + for (const auto &op : ops) { + hasBallparkTransformation |= op->hasBallparkTransformation(); + } auto extent = getExtent(ops, true, dummy); auto properties = util::PropertyMap(); properties.set(common::IdentifiedObject::NAME_KEY, @@ -10728,7 +11208,7 @@ static CoordinateOperationNNPtr createHorizVerticalHorizPROJBased( } return createPROJBased(properties, exportable, sourceCRS, targetCRS, - accuracies); + accuracies, hasBallparkTransformation); } //! @endcond @@ -10784,6 +11264,11 @@ CoordinateOperationFactory::Private::createOperationsGeogToGeog( std::string name(buildTransfName(geogSrc->nameStr(), geogDst->nameStr())); + const bool sameDatum = + geogSrc->datum() != nullptr && geogDst->datum() != nullptr && + geogSrc->datum()->_isEquivalentTo( + geogDst->datum().get(), util::IComparable::Criterion::EQUIVALENT); + // Do they differ by vertical units ? if (vconvSrc != vconvDst && geogSrc->ellipsoid()->_isEquivalentTo( @@ -10799,18 +11284,19 @@ CoordinateOperationFactory::Private::createOperationsGeogToGeog( name), common::Scale(factor)); conv->setCRSs(sourceCRS, targetCRS, nullptr); + conv->setHasBallparkTransformation(!sameDatum); res.push_back(conv); return res; } else { - res.emplace_back(createGeodToGeodPROJBased(sourceCRS, targetCRS)); + auto op = createGeodToGeodPROJBased(sourceCRS, targetCRS); + op->setHasBallparkTransformation(!sameDatum); + res.emplace_back(op); return res; } } // Do the CRS differ only by their axis order ? - if (geogSrc->datum() != nullptr && geogDst->datum() != nullptr && - geogSrc->datum()->_isEquivalentTo( - geogDst->datum().get(), util::IComparable::Criterion::EQUIVALENT) && + if (sameDatum && !srcCS->_isEquivalentTo(dstCS.get(), util::IComparable::Criterion::EQUIVALENT)) { auto srcOrder = srcCS->axisOrder(); @@ -10871,7 +11357,8 @@ CoordinateOperationFactory::Private::createOperationsGeogToGeog( metadata::Extent::WORLD), datum, dstCS)); - steps.emplace_back(createNullGeographicOffset(sourceCRS, interm_crs)); + steps.emplace_back( + createBallparkGeographicOffset(sourceCRS, interm_crs)); steps.emplace_back(Transformation::createLongitudeRotation( util::PropertyMap() @@ -10906,15 +11393,17 @@ CoordinateOperationFactory::Private::createOperationsGeogToGeog( metadata::Extent::WORLD), sourceCRS, interm_crs, offset_pm)); steps.emplace_back( - createNullGeographicOffset(interm_crs, targetCRS)); + createBallparkGeographicOffset(interm_crs, targetCRS)); } else { steps.emplace_back( - createNullGeographicOffset(sourceCRS, targetCRS)); + createBallparkGeographicOffset(sourceCRS, targetCRS)); } } - res.emplace_back(ConcatenatedOperation::createComputeMetadata( - steps, !allowEmptyIntersection)); + auto op = ConcatenatedOperation::createComputeMetadata( + steps, !allowEmptyIntersection); + op->setHasBallparkTransformation(!sameDatum); + res.emplace_back(op); return res; } @@ -10946,16 +11435,37 @@ static bool hasIdentifiers(const CoordinateOperationNNPtr &op) { static std::vector<crs::CRSNNPtr> findCandidateGeodCRSForDatum(const io::AuthorityFactoryPtr &authFactory, - const datum::GeodeticReferenceFramePtr &datum) { + const datum::GeodeticReferenceFrame *datum) { std::vector<crs::CRSNNPtr> candidates; - for (const auto &id : datum->identifiers()) { - const auto &authName = *(id->codeSpace()); - const auto &code = id->code(); - if (!authName.empty()) { - auto l_candidates = authFactory->createGeodeticCRSFromDatum( - authName, code, std::string()); - for (const auto &candidate : l_candidates) { - candidates.emplace_back(candidate); + assert(datum); + const auto &ids = datum->identifiers(); + const auto &datumName = datum->nameStr(); + if (!ids.empty()) { + for (const auto &id : ids) { + const auto &authName = *(id->codeSpace()); + const auto &code = id->code(); + if (!authName.empty()) { + auto l_candidates = authFactory->createGeodeticCRSFromDatum( + authName, code, std::string()); + for (const auto &candidate : l_candidates) { + candidates.emplace_back(candidate); + } + } + } + } else if (datumName != "unknown" && datumName != "unnamed") { + auto matches = authFactory->createObjectsFromName( + datumName, + {io::AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME}, false, + 2); + if (matches.size() == 1) { + const auto &match = matches.front(); + if (datum->_isEquivalentTo( + match.get(), util::IComparable::Criterion::EQUIVALENT) && + !match->identifiers().empty()) { + return findCandidateGeodCRSForDatum( + authFactory, + dynamic_cast<const datum::GeodeticReferenceFrame *>( + match.get())); } } } @@ -10966,17 +11476,53 @@ findCandidateGeodCRSForDatum(const io::AuthorityFactoryPtr &authFactory, static bool isNullTransformation(const std::string &name) { - return starts_with(name, NULL_GEOCENTRIC_TRANSLATION) || + return starts_with(name, BALLPARK_GEOCENTRIC_TRANSLATION) || + starts_with(name, BALLPARK_GEOGRAPHIC_OFFSET) || starts_with(name, NULL_GEOGRAPHIC_OFFSET); } // --------------------------------------------------------------------------- +#ifdef DEBUG + +static int nCallLevel = 0; + +struct EnterDebugLevel { + EnterDebugLevel() { ++nCallLevel; } + ~EnterDebugLevel() { --nCallLevel; } +}; + +static void debugTrace(const std::string &str) { + for (int i = 1; i < nCallLevel; i++) + std::cerr << " "; + std::cerr << str << std::endl; +} + +static std::string objectAsStr(const common::IdentifiedObject *obj) { + std::string ret(obj->nameStr()); + const auto &ids = obj->identifiers(); + if (!ids.empty()) { + ret += " ("; + ret += (*ids[0]->codeSpace()) + ":" + ids[0]->code(); + ret += ")"; + } + return ret; +} +#endif + +// --------------------------------------------------------------------------- + void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( std::vector<CoordinateOperationNNPtr> &res, const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, const crs::GeodeticCRS *geodSrc, const crs::GeodeticCRS *geodDst, Private::Context &context) { +#ifdef DEBUG + EnterDebugLevel enterFunction; + debugTrace("createOperationsWithDatumPivot(" + + objectAsStr(sourceCRS.get()) + "," + + objectAsStr(targetCRS.get()) + ")"); +#endif const bool allowEmptyIntersection = true; struct CreateOperationsWithDatumPivotAntiRecursion { @@ -10996,9 +11542,9 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( const auto &authFactory = context.context->getAuthorityFactory(); const auto candidatesSrcGeod( - findCandidateGeodCRSForDatum(authFactory, geodSrc->datum())); + findCandidateGeodCRSForDatum(authFactory, geodSrc->datum().get())); const auto candidatesDstGeod( - findCandidateGeodCRSForDatum(authFactory, geodDst->datum())); + findCandidateGeodCRSForDatum(authFactory, geodDst->datum().get())); auto createTransformations = [&](const crs::CRSNNPtr &candidateSrcGeod, const crs::CRSNNPtr &candidateDstGeod, @@ -11024,20 +11570,73 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( } std::vector<CoordinateOperationNNPtr> subOps; + const bool isNullThird = + isNullTransformation(opsThird[0]->nameStr()); + CoordinateOperationNNPtr opSecondCloned( + (isNullFirst || isNullThird) ? opSecond->shallowClone() + : opSecond); + CoordinateOperation *invCOForward = nullptr; + if (isNullFirst || isNullThird) { + if (opSecondCloned->identifiers().size() == 1 && + (*opSecondCloned->identifiers()[0]->codeSpace()) + .find("DERIVED_FROM") == std::string::npos) { + { + util::PropertyMap map; + addModifiedIdentifier(map, opSecondCloned.get(), false, + true); + opSecondCloned->setProperties(map); + } + auto invCO = dynamic_cast<InverseCoordinateOperation *>( + opSecondCloned.get()); + if (invCO) { + invCOForward = invCO->forwardOperation().get(); + if (invCOForward->identifiers().size() == 1 && + (*invCOForward->identifiers()[0]->codeSpace()) + .find("DERIVED_FROM") == + std::string::npos) { + util::PropertyMap map; + addModifiedIdentifier(map, invCOForward, false, + true); + invCOForward->setProperties(map); + } + } + } + } if (isNullFirst) { - opSecond->setCRSs( - sourceCRS, NN_CHECK_ASSERT(opSecond->targetCRS()), nullptr); + auto oldTarget(NN_CHECK_ASSERT(opSecondCloned->targetCRS())); + opSecondCloned->setCRSs(sourceCRS, oldTarget, nullptr); + if (invCOForward) { + invCOForward->setCRSs(oldTarget, sourceCRS, nullptr); + } } else { subOps.emplace_back(opFirst); } - if (isNullTransformation(opsThird[0]->nameStr())) { - opSecond->setCRSs(NN_CHECK_ASSERT(opSecond->sourceCRS()), - targetCRS, nullptr); - subOps.emplace_back(opSecond); + if (isNullThird) { + auto oldSource(NN_CHECK_ASSERT(opSecondCloned->sourceCRS())); + opSecondCloned->setCRSs(oldSource, targetCRS, nullptr); + if (invCOForward) { + invCOForward->setCRSs(targetCRS, oldSource, nullptr); + } + subOps.emplace_back(opSecondCloned); } else { - subOps.emplace_back(opSecond); + subOps.emplace_back(opSecondCloned); subOps.emplace_back(opsThird[0]); } +#ifdef DEBUG + std::string debugStr; + for (const auto &op : subOps) { + if (!debugStr.empty()) { + debugStr += " + "; + } + debugStr += objectAsStr(op.get()); + debugStr += " ("; + debugStr += objectAsStr(op->sourceCRS().get()); + debugStr += "->"; + debugStr += objectAsStr(op->targetCRS().get()); + debugStr += ")"; + } + debugTrace("transformation " + debugStr); +#endif res.emplace_back(ConcatenatedOperation::createComputeMetadata( subOps, !allowEmptyIntersection)); } @@ -11049,6 +11648,14 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( if (candidateSrcGeod->nameStr() == sourceCRS->nameStr()) { for (const auto &candidateDstGeod : candidatesDstGeod) { if (candidateDstGeod->nameStr() == targetCRS->nameStr()) { +#ifdef DEBUG + EnterDebugLevel loopLevel; + debugTrace("try " + objectAsStr(sourceCRS.get()) + "->" + + objectAsStr(candidateSrcGeod.get()) + "->" + + objectAsStr(candidateDstGeod.get()) + "->" + + objectAsStr(targetCRS.get()) + ")"); + EnterDebugLevel loopLevel2; +#endif const auto opsFirst = createOperations(sourceCRS, candidateSrcGeod, context); assert(!opsFirst.empty()); @@ -11067,17 +11674,28 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( } for (const auto &candidateSrcGeod : candidatesSrcGeod) { +#ifdef DEBUG + EnterDebugLevel loopLevel; +#endif const auto opsFirst = createOperations(sourceCRS, candidateSrcGeod, context); assert(!opsFirst.empty()); const bool isNullFirst = isNullTransformation(opsFirst[0]->nameStr()); for (const auto &candidateDstGeod : candidatesDstGeod) { +#ifdef DEBUG + EnterDebugLevel loopLevel2; + debugTrace("try " + objectAsStr(sourceCRS.get()) + "->" + + objectAsStr(candidateSrcGeod.get()) + "->" + + objectAsStr(candidateDstGeod.get()) + "->" + + objectAsStr(targetCRS.get()) + ")"); + EnterDebugLevel loopLevel3; +#endif createTransformations(candidateSrcGeod, candidateDstGeod, opsFirst[0], isNullFirst); - } - if (!res.empty()) { - return; + if (!res.empty()) { + return; + } } } } @@ -11085,9 +11703,9 @@ void CoordinateOperationFactory::Private::createOperationsWithDatumPivot( // --------------------------------------------------------------------------- static CoordinateOperationNNPtr -createNullGeocentricTranslation(const crs::CRSNNPtr &sourceCRS, - const crs::CRSNNPtr &targetCRS) { - std::string name(NULL_GEOCENTRIC_TRANSLATION); +createBallparkGeocentricTranslation(const crs::CRSNNPtr &sourceCRS, + const crs::CRSNNPtr &targetCRS) { + std::string name(BALLPARK_GEOCENTRIC_TRANSLATION); name += " from "; name += sourceCRS->nameStr(); name += " to "; @@ -11132,6 +11750,13 @@ CoordinateOperationFactory::Private::createOperations( const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, Private::Context &context) { +#ifdef DEBUG + EnterDebugLevel enterFunction; + auto debugStr("createOperations(" + objectAsStr(sourceCRS.get()) + "," + + objectAsStr(targetCRS.get()) + ")"); + debugTrace(debugStr); +#endif + std::vector<CoordinateOperationNNPtr> res; const bool allowEmptyIntersection = true; @@ -11211,15 +11836,48 @@ CoordinateOperationFactory::Private::createOperations( doFilterAndCheckPerfectOp = false; + bool sameGeodeticDatum = false; + if (geodSrc && geodDst) { + const auto &srcDatum = geodSrc->datum(); + const auto &dstDatum = geodDst->datum(); + sameGeodeticDatum = + srcDatum != nullptr && dstDatum != nullptr && + srcDatum->_isEquivalentTo( + dstDatum.get(), + util::IComparable::Criterion::EQUIVALENT); + } + + if (res.empty() && !sameGeodeticDatum && + !context.inCreateOperationsWithDatumPivotAntiRecursion && + geodSrc && geodDst) { + // If we still didn't find a transformation, and that the source + // and target are GeodeticCRS, then go through their underlying + // datum to find potential transformations between other + // GeodeticRSs + // that are made of those datum + // The typical example is if transforming between two + // GeographicCRS, + // but transformations are only available between their + // corresponding geocentric CRS. + const auto &srcDatum = geodSrc->datum(); + const auto &dstDatum = geodDst->datum(); + if (srcDatum != nullptr && dstDatum != nullptr) { + createOperationsWithDatumPivot(res, sourceCRS, targetCRS, + geodSrc, geodDst, context); + doFilterAndCheckPerfectOp = !res.empty(); + } + } + // NAD27 to NAD83 has tens of results already. No need to look // for a pivot - if ((res.empty() && + if (!sameGeodeticDatum && + ((res.empty() && + context.context->getAllowUseIntermediateCRS() == + CoordinateOperationContext::IntermediateCRSUse:: + IF_NO_DIRECT_TRANSFORMATION) || context.context->getAllowUseIntermediateCRS() == - CoordinateOperationContext::IntermediateCRSUse:: - IF_NO_DIRECT_TRANSFORMATION) || - context.context->getAllowUseIntermediateCRS() == - CoordinateOperationContext::IntermediateCRSUse::ALWAYS || - getenv("PROJ_FORCE_SEARCH_PIVOT")) { + CoordinateOperationContext::IntermediateCRSUse::ALWAYS || + getenv("PROJ_FORCE_SEARCH_PIVOT"))) { auto resWithIntermediate = findsOpsInRegistryWithIntermediate( sourceCRS, targetCRS, context.context); res.insert(res.end(), resWithIntermediate.begin(), @@ -11228,31 +11886,6 @@ CoordinateOperationFactory::Private::createOperations( } } - if (res.empty() && - !context.inCreateOperationsWithDatumPivotAntiRecursion && geodSrc && - geodDst) { - // If we still didn't find a transformation, and that the source - // and target are GeodeticCRS, then go through their underlying - // datum to find potential transformations between other GeodeticRSs - // that are made of those datum - // The typical example is if transforming between two GeographicCRS, - // but transformations are only available between their - // corresponding geocentric CRS. - const auto &srcDatum = geodSrc->datum(); - const bool srcHasDatumWithId = - srcDatum && !srcDatum->identifiers().empty(); - const auto &dstDatum = geodDst->datum(); - const bool dstHasDatumWithId = - dstDatum && !dstDatum->identifiers().empty(); - if (srcHasDatumWithId && dstHasDatumWithId && - !srcDatum->_isEquivalentTo( - dstDatum.get(), util::IComparable::Criterion::EQUIVALENT)) { - createOperationsWithDatumPivot(res, sourceCRS, targetCRS, - geodSrc, geodDst, context); - doFilterAndCheckPerfectOp = !res.empty(); - } - } - if (doFilterAndCheckPerfectOp) { // If we get at least a result with perfect accuracy, do not bother // generating synthetic transforms. @@ -11309,7 +11942,7 @@ CoordinateOperationFactory::Private::createOperations( util::nn_dynamic_pointer_cast<cs::CartesianCS>( geodSrc->coordinateSystem())))); auto opFirst = - createNullGeocentricTranslation(sourceCRS, interm_crs); + createBallparkGeocentricTranslation(sourceCRS, interm_crs); auto opSecond = createGeographicGeocentric(interm_crs, targetCRS); res.emplace_back(ConcatenatedOperation::createComputeMetadata( @@ -11324,7 +11957,7 @@ CoordinateOperationFactory::Private::createOperations( if (isSrcGeocentric && isTargetGeocentric) { res.emplace_back( - createNullGeocentricTranslation(sourceCRS, targetCRS)); + createBallparkGeocentricTranslation(sourceCRS, targetCRS)); return res; } @@ -11363,7 +11996,6 @@ CoordinateOperationFactory::Private::createOperations( return applyInverse(createOperations(targetCRS, sourceCRS, context)); } - // boundCRS to a geogCRS that is the same as the hubCRS auto boundSrc = dynamic_cast<const crs::BoundCRS *>(sourceCRS.get()); auto geogDst = dynamic_cast<const crs::GeographicCRS *>(targetCRS.get()); if (boundSrc && geogDst) { @@ -11372,6 +12004,7 @@ CoordinateOperationFactory::Private::createOperations( dynamic_cast<const crs::GeographicCRS *>(hubSrc.get()); auto geogCRSOfBaseOfBoundSrc = boundSrc->baseCRS()->extractGeographicCRS(); + // Is it: boundCRS to a geogCRS that is the same as the hubCRS ? if (hubSrcGeog && geogCRSOfBaseOfBoundSrc && (hubSrcGeog->_isEquivalentTo( geogDst, util::IComparable::Criterion::EQUIVALENT) || @@ -11489,6 +12122,66 @@ CoordinateOperationFactory::Private::createOperations( return res; } + if (hubSrcGeog && geogCRSOfBaseOfBoundSrc) { + // This one should go to the above 'Is it: boundCRS to a geogCRS + // that is the same as the hubCRS ?' case + auto opsFirst = createOperations(sourceCRS, hubSrc, context); + auto opsLast = createOperations(hubSrc, targetCRS, context); + if (!opsFirst.empty() && !opsLast.empty()) { + for (const auto &opFirst : opsFirst) { + for (const auto &opLast : opsLast) { + // Exclude artificial transformations from the hub + // to the target CRS + if (!opLast->hasBallparkTransformation()) { + try { + res.emplace_back( + ConcatenatedOperation:: + createComputeMetadata( + {opFirst, opLast}, + !allowEmptyIntersection)); + } catch ( + const InvalidOperationEmptyIntersection &) { + } + } + } + } + if (!res.empty()) { + return res; + } + } + } + + auto vertCRSOfBaseOfBoundSrc = + dynamic_cast<const crs::VerticalCRS *>(boundSrc->baseCRS().get()); + if (vertCRSOfBaseOfBoundSrc && hubSrcGeog && + hubSrcGeog->coordinateSystem()->axisList().size() == 3 && + geogDst->coordinateSystem()->axisList().size() == 3) { + auto opsFirst = createOperations(sourceCRS, hubSrc, context); + auto opsSecond = createOperations(hubSrc, targetCRS, context); + if (!opsFirst.empty() && !opsSecond.empty()) { + for (const auto &opFirst : opsFirst) { + for (const auto &opLast : opsSecond) { + // Exclude artificial transformations from the hub + // to the target CRS + if (!opLast->hasBallparkTransformation()) { + try { + res.emplace_back( + ConcatenatedOperation:: + createComputeMetadata( + {opFirst, opLast}, + !allowEmptyIntersection)); + } catch ( + const InvalidOperationEmptyIntersection &) { + } + } + } + } + if (!res.empty()) { + return res; + } + } + } + return createOperations(boundSrc->baseCRS(), targetCRS, context); } @@ -11526,35 +12219,65 @@ CoordinateOperationFactory::Private::createOperations( if (vertSrc && vertDst) { const auto &srcDatum = vertSrc->datum(); const auto &dstDatum = vertDst->datum(); - if (srcDatum && dstDatum && - srcDatum->_isEquivalentTo( - dstDatum.get(), util::IComparable::Criterion::EQUIVALENT)) { - const double convSrc = vertSrc->coordinateSystem() - ->axisList()[0] - ->unit() - .conversionToSI(); - const double convDst = vertDst->coordinateSystem() - ->axisList()[0] - ->unit() - .conversionToSI(); - if (convSrc != convDst) { - const double factor = convSrc / convDst; - auto conv = Conversion::createChangeVerticalUnit( - util::PropertyMap().set( - common::IdentifiedObject::NAME_KEY, - buildTransfName(sourceCRS->nameStr(), - targetCRS->nameStr())), - common::Scale(factor)); - conv->setCRSs(sourceCRS, targetCRS, nullptr); - res.push_back(conv); - return res; - } + const bool equivalentVDatum = + (srcDatum && dstDatum && + srcDatum->_isEquivalentTo( + dstDatum.get(), util::IComparable::Criterion::EQUIVALENT)); + + const double convSrc = + vertSrc->coordinateSystem()->axisList()[0]->unit().conversionToSI(); + const double convDst = + vertDst->coordinateSystem()->axisList()[0]->unit().conversionToSI(); + + const double factor = convSrc / convDst; + auto name = buildTransfName(sourceCRS->nameStr(), targetCRS->nameStr()); + if (!equivalentVDatum) { + name += BALLPARK_VERTICAL_TRANSFORMATION; + auto conv = Transformation::createChangeVerticalUnit( + util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, + name), + sourceCRS, targetCRS, common::Scale(factor), {}); + conv->setHasBallparkTransformation(true); + res.push_back(conv); + } else if (convSrc != convDst) { + auto conv = Conversion::createChangeVerticalUnit( + util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, + name), + common::Scale(factor)); + conv->setCRSs(sourceCRS, targetCRS, nullptr); + res.push_back(conv); } + return res; } // A bit odd case as we are comparing apples to oranges, but in case // the vertical unit differ, do something useful. if (vertSrc && geogDst) { + + if (vertSrc->identifiers().empty()) { + const auto &authFactory = context.context->getAuthorityFactory(); + const auto &vertSrcName = vertSrc->nameStr(); + if (authFactory != nullptr && vertSrcName != "unnamed" && + vertSrcName != "unknown") { + auto matches = authFactory->createObjectsFromName( + vertSrcName, + {io::AuthorityFactory::ObjectType::VERTICAL_CRS}, false, 2); + if (matches.size() == 1) { + const auto &match = matches.front(); + if (vertSrc->_isEquivalentTo( + match.get(), + util::IComparable::Criterion::EQUIVALENT) && + !match->identifiers().empty()) { + return createOperations( + NN_NO_CHECK( + util::nn_dynamic_pointer_cast<crs::VerticalCRS>( + match)), + targetCRS, context); + } + } + } + } + const double convSrc = vertSrc->coordinateSystem()->axisList()[0]->unit().conversionToSI(); double convDst = 1.0; @@ -11562,17 +12285,17 @@ CoordinateOperationFactory::Private::createOperations( if (geogAxis.size() == 3) { convDst = geogAxis[2]->unit().conversionToSI(); } - if (convSrc != convDst) { - const double factor = convSrc / convDst; - auto conv = Conversion::createChangeVerticalUnit( - util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, - buildTransfName(sourceCRS->nameStr(), - targetCRS->nameStr())), - common::Scale(factor)); - conv->setCRSs(sourceCRS, targetCRS, nullptr); - res.push_back(conv); - return res; - } + + const double factor = convSrc / convDst; + auto conv = Transformation::createChangeVerticalUnit( + util::PropertyMap().set( + common::IdentifiedObject::NAME_KEY, + buildTransfName(sourceCRS->nameStr(), targetCRS->nameStr()) + + BALLPARK_VERTICAL_TRANSFORMATION_NO_ELLIPSOID_VERT_HEIGHT), + sourceCRS, targetCRS, common::Scale(factor), {}); + conv->setHasBallparkTransformation(true); + res.push_back(conv); + return res; } // reverse of previous case @@ -11636,6 +12359,34 @@ CoordinateOperationFactory::Private::createOperations( } } + auto vertCRSOfBaseOfBoundSrc = + boundSrc->baseCRS()->extractVerticalCRS(); + auto vertCRSOfBaseOfBoundDst = + boundDst->baseCRS()->extractVerticalCRS(); + if (hubSrcGeog && hubDstGeog && + hubSrcGeog->_isEquivalentTo( + hubDstGeog, util::IComparable::Criterion::EQUIVALENT) && + vertCRSOfBaseOfBoundSrc && vertCRSOfBaseOfBoundDst) { + auto opsFirst = createOperations(sourceCRS, hubSrc, context); + auto opsLast = createOperations(hubSrc, targetCRS, context); + if (!opsFirst.empty() && !opsLast.empty()) { + for (const auto &opFirst : opsFirst) { + for (const auto &opLast : opsLast) { + try { + res.emplace_back( + ConcatenatedOperation::createComputeMetadata( + {opFirst, opLast}, + !allowEmptyIntersection)); + } catch (const InvalidOperationEmptyIntersection &) { + } + } + } + if (!res.empty()) { + return res; + } + } + } + return createOperations(boundSrc->baseCRS(), boundDst->baseCRS(), context); } @@ -11645,7 +12396,8 @@ CoordinateOperationFactory::Private::createOperations( const auto &componentsSrc = compoundSrc->componentReferenceSystems(); if (!componentsSrc.empty()) { std::vector<CoordinateOperationNNPtr> horizTransforms; - if (componentsSrc[0]->extractGeographicCRS()) { + auto srcGeogCRS = componentsSrc[0]->extractGeographicCRS(); + if (srcGeogCRS) { horizTransforms = createOperations(componentsSrc[0], targetCRS, context); } @@ -11659,11 +12411,61 @@ CoordinateOperationFactory::Private::createOperations( for (const auto &horizTransform : horizTransforms) { for (const auto &verticalTransform : verticalTransforms) { - auto op = createHorizVerticalPROJBased( - sourceCRS, targetCRS, horizTransform, - verticalTransform); + crs::GeographicCRSPtr interpolationGeogCRS; + auto transformationVerticalTransform = + dynamic_cast<const Transformation *>( + verticalTransform.get()); + if (transformationVerticalTransform) { + auto interpTransformCRS = + transformationVerticalTransform + ->interpolationCRS(); + if (interpTransformCRS) { + auto nn_interpTransformCRS = + NN_NO_CHECK(interpTransformCRS); + if (dynamic_cast<const crs::GeographicCRS *>( + nn_interpTransformCRS.get())) { + interpolationGeogCRS = + util::nn_dynamic_pointer_cast< + crs::GeographicCRS>( + nn_interpTransformCRS); + } + } + } + bool done = false; + if (interpolationGeogCRS && + (interpolationGeogCRS->_isEquivalentTo( + srcGeogCRS.get(), + util::IComparable::Criterion::EQUIVALENT) || + interpolationGeogCRS->is2DPartOf3D( + NN_NO_CHECK(srcGeogCRS.get())))) { + auto srcToInterp = createOperations( + componentsSrc[0], + NN_NO_CHECK(interpolationGeogCRS), context); + auto interpToCompoundHoriz = createOperations( + NN_NO_CHECK(interpolationGeogCRS), + componentsSrc[0], context); + if (!srcToInterp.empty() && + !interpToCompoundHoriz.empty()) { + auto op = createHorizVerticalHorizPROJBased( + sourceCRS, componentsSrc[0], + srcToInterp.front(), verticalTransform, + interpToCompoundHoriz.front(), + interpolationGeogCRS); + done = true; + res.emplace_back( + ConcatenatedOperation:: + createComputeMetadata( + {op, horizTransform}, + !allowEmptyIntersection)); + } + } + if (!done) { + auto op = createHorizVerticalPROJBased( + sourceCRS, targetCRS, horizTransform, + verticalTransform); - res.emplace_back(op); + res.emplace_back(op); + } } } return res; @@ -11671,11 +12473,40 @@ CoordinateOperationFactory::Private::createOperations( return horizTransforms; } } + } else if (compoundSrc && geodDst) { + auto datum = geodDst->datum(); + if (datum) { + auto cs = + cs::EllipsoidalCS::createLatitudeLongitudeEllipsoidalHeight( + common::UnitOfMeasure::DEGREE, + common::UnitOfMeasure::METRE); + auto intermGeog3DCRS = util::nn_static_pointer_cast<crs::CRS>( + crs::GeographicCRS::create( + util::PropertyMap() + .set(common::IdentifiedObject::NAME_KEY, + geodDst->nameStr()) + .set(common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, + metadata::Extent::WORLD), + NN_NO_CHECK(datum), cs)); + auto sourceToGeog3DOps = + createOperations(sourceCRS, intermGeog3DCRS, context); + auto geog3DToTargetOps = + createOperations(intermGeog3DCRS, targetCRS, context); + if (!geog3DToTargetOps.empty()) { + for (const auto &op : sourceToGeog3DOps) { + res.emplace_back( + ConcatenatedOperation::createComputeMetadata( + {op, geog3DToTargetOps.front()}, + !allowEmptyIntersection)); + } + return res; + } + } } // reverse of previous case auto compoundDst = dynamic_cast<const crs::CompoundCRS *>(targetCRS.get()); - if (geogSrc && compoundDst) { + if (geodSrc && compoundDst) { return applyInverse(createOperations(targetCRS, sourceCRS, context)); } @@ -11715,6 +12546,21 @@ CoordinateOperationFactory::Private::createOperations( nn_interpTransformCRS)); } } + } else { + auto compSrc0BoundCrs = dynamic_cast<crs::BoundCRS *>( + componentsSrc[0].get()); + auto compDst0BoundCrs = dynamic_cast<crs::BoundCRS *>( + componentsDst[0].get()); + if (compSrc0BoundCrs && compDst0BoundCrs && + dynamic_cast<crs::GeographicCRS *>( + compSrc0BoundCrs->hubCRS().get()) && + compSrc0BoundCrs->hubCRS()->_isEquivalentTo( + compDst0BoundCrs->hubCRS().get())) { + interpolationGeogCRS = + NN_NO_CHECK(util::nn_dynamic_pointer_cast< + crs::GeographicCRS>( + compSrc0BoundCrs->hubCRS())); + } } auto opSrcCRSToGeogCRS = createOperations( componentsSrc[0], interpolationGeogCRS, context); @@ -11739,12 +12585,157 @@ CoordinateOperationFactory::Private::createOperations( } } + // '+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +type=crs' to + // '+proj=longlat +ellps=GRS80 +nadgrids=@bar.gsb +geoidgrids=@bar.gtx + // +type=crs' + if (boundSrc && compoundDst) { + const auto &componentsDst = compoundDst->componentReferenceSystems(); + if (!componentsDst.empty()) { + auto compDst0BoundCrs = + dynamic_cast<crs::BoundCRS *>(componentsDst[0].get()); + if (compDst0BoundCrs) { + auto boundSrcHubAsGeogCRS = dynamic_cast<crs::GeographicCRS *>( + boundSrc->hubCRS().get()); + auto compDst0BoundCrsHubAsGeogCRS = + dynamic_cast<crs::GeographicCRS *>( + compDst0BoundCrs->hubCRS().get()); + if (boundSrcHubAsGeogCRS && compDst0BoundCrsHubAsGeogCRS) { + const auto &boundSrcHubAsGeogCRSDatum = + boundSrcHubAsGeogCRS->datum(); + const auto &compDst0BoundCrsHubAsGeogCRSDatum = + compDst0BoundCrsHubAsGeogCRS->datum(); + if (boundSrcHubAsGeogCRSDatum && + compDst0BoundCrsHubAsGeogCRSDatum && + boundSrcHubAsGeogCRSDatum->_isEquivalentTo( + compDst0BoundCrsHubAsGeogCRSDatum.get())) { + auto cs = cs::EllipsoidalCS:: + createLatitudeLongitudeEllipsoidalHeight( + common::UnitOfMeasure::DEGREE, + common::UnitOfMeasure::METRE); + auto intermGeog3DCRS = util::nn_static_pointer_cast< + crs::CRS>(crs::GeographicCRS::create( + util::PropertyMap() + .set(common::IdentifiedObject::NAME_KEY, + boundSrcHubAsGeogCRS->nameStr()) + .set( + common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, + metadata::Extent::WORLD), + NN_NO_CHECK(boundSrcHubAsGeogCRSDatum), cs)); + auto sourceToGeog3DOps = createOperations( + sourceCRS, intermGeog3DCRS, context); + auto geog3DToTargetOps = createOperations( + intermGeog3DCRS, targetCRS, context); + for (const auto &opSrc : sourceToGeog3DOps) { + for (const auto &opDst : geog3DToTargetOps) { + if (opSrc->targetCRS() && opDst->sourceCRS() && + !opSrc->targetCRS()->_isEquivalentTo( + opDst->sourceCRS().get())) { + // Shouldn't happen normally, but typically + // one of them can be 2D and the other 3D + // due to above createOperations() not + // exactly setting the expected source and + // target CRS. + // So create an adapter operation... + auto intermOps = createOperations( + NN_NO_CHECK(opSrc->targetCRS()), + NN_NO_CHECK(opDst->sourceCRS()), + context); + if (!intermOps.empty()) { + res.emplace_back( + ConcatenatedOperation:: + createComputeMetadata( + {opSrc, intermOps.front(), + opDst}, + !allowEmptyIntersection)); + } + } else { + res.emplace_back( + ConcatenatedOperation:: + createComputeMetadata( + {opSrc, opDst}, + !allowEmptyIntersection)); + } + } + } + } + } + } + } + } + + // reverse of previous case + if (boundDst && compoundSrc) { + return applyInverse(createOperations(targetCRS, sourceCRS, context)); + } + return res; } //! @endcond // --------------------------------------------------------------------------- +static crs::CRSNNPtr +getResolvedCRS(const crs::CRSNNPtr &crs, + const CoordinateOperationContextNNPtr &context) { + const auto &authFactory = context->getAuthorityFactory(); + + auto projectedCrs = dynamic_cast<crs::ProjectedCRS *>(crs.get()); + if (projectedCrs && authFactory) { + const auto &ids = projectedCrs->identifiers(); + if (!ids.empty() && projectedCrs->baseCRS()->identifiers().empty()) { + const auto tmpAuthFactory = io::AuthorityFactory::create( + authFactory->databaseContext(), *ids.front()->codeSpace()); + try { + auto resolvedCrs( + tmpAuthFactory->createProjectedCRS(ids.front()->code())); + if (resolvedCrs->isEquivalentTo( + crs.get(), util::IComparable::Criterion::EQUIVALENT)) { + return util::nn_static_pointer_cast<crs::CRS>(resolvedCrs); + } + } catch (const std::exception &) { + } + } + } + + auto compoundCrs = dynamic_cast<crs::CompoundCRS *>(crs.get()); + // If we get a CompoundCRS that has an EPSG code, but whose component CRS + // lack one, typically from WKT2, this might be an issue to get proper + // results in createOperations(), so import the CompoundCRS from the + // registry, and if equivalent to the original one, then use the version + // from the registry. + if (compoundCrs && authFactory) { + const auto &ids = compoundCrs->identifiers(); + if (!ids.empty()) { + const auto &components = compoundCrs->componentReferenceSystems(); + bool hasMissingId = false; + for (const auto &comp : components) { + if (comp->identifiers().empty()) { + hasMissingId = true; + break; + } + } + if (hasMissingId) { + const auto tmpAuthFactory = io::AuthorityFactory::create( + authFactory->databaseContext(), *ids.front()->codeSpace()); + try { + auto resolvedCrs( + tmpAuthFactory->createCompoundCRS(ids.front()->code())); + if (resolvedCrs->isEquivalentTo( + crs.get(), + util::IComparable::Criterion::EQUIVALENT)) { + return util::nn_static_pointer_cast<crs::CRS>( + resolvedCrs); + } + } catch (const std::exception &) { + } + } + } + } + return crs; +} + +// --------------------------------------------------------------------------- + /** \brief Find a list of CoordinateOperation from sourceCRS to targetCRS. * * The operations are sorted with the most relevant ones first: by @@ -11773,10 +12764,25 @@ CoordinateOperationFactory::createOperations( auto l_sourceCRS = srcBoundCRS ? NN_NO_CHECK(srcBoundCRS) : sourceCRS; auto l_targetCRS = targetBoundCRS ? NN_NO_CHECK(targetBoundCRS) : targetCRS; - Private::Context contextPrivate(sourceCRS, targetCRS, context); - return filterAndSort( - Private::createOperations(l_sourceCRS, l_targetCRS, contextPrivate), - context, l_sourceCRS, l_targetCRS); + auto l_resolvedSourceCRS = getResolvedCRS(l_sourceCRS, context); + auto l_resolvedTargetCRS = getResolvedCRS(l_targetCRS, context); + Private::Context contextPrivate(l_resolvedSourceCRS, l_resolvedTargetCRS, + context); + + if (context->getSourceAndTargetCRSExtentUse() == + CoordinateOperationContext::SourceTargetCRSExtentUse::INTERSECTION) { + auto sourceCRSExtent(getExtent(l_resolvedSourceCRS)); + auto targetCRSExtent(getExtent(l_resolvedTargetCRS)); + if (sourceCRSExtent && targetCRSExtent && + !sourceCRSExtent->intersects(NN_NO_CHECK(targetCRSExtent))) { + return std::vector<CoordinateOperationNNPtr>(); + } + } + + return filterAndSort(Private::createOperations(l_resolvedSourceCRS, + l_resolvedTargetCRS, + contextPrivate), + context, l_resolvedSourceCRS, l_resolvedTargetCRS); } // --------------------------------------------------------------------------- @@ -11797,8 +12803,9 @@ InverseCoordinateOperation::~InverseCoordinateOperation() = default; // --------------------------------------------------------------------------- InverseCoordinateOperation::InverseCoordinateOperation( - const CoordinateOperationNNPtr &forwardOperation, bool wktSupportsInversion) - : forwardOperation_(forwardOperation), + const CoordinateOperationNNPtr &forwardOperationIn, + bool wktSupportsInversion) + : forwardOperation_(forwardOperationIn), wktSupportsInversion_(wktSupportsInversion) {} // --------------------------------------------------------------------------- @@ -11810,6 +12817,8 @@ void InverseCoordinateOperation::setPropertiesFromForward() { if (forwardOperation_->sourceCRS() && forwardOperation_->targetCRS()) { setCRSs(forwardOperation_.get(), true); } + setHasBallparkTransformation( + forwardOperation_->hasBallparkTransformation()); } // --------------------------------------------------------------------------- @@ -11877,7 +12886,8 @@ PROJBasedOperationNNPtr PROJBasedOperation::create( const util::PropertyMap &properties, const io::IPROJStringExportableNNPtr &projExportable, bool inverse, const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, - const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies) { + const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies, + bool hasBallparkTransformation) { auto formatter = io::PROJStringFormatter::create(); if (inverse) { @@ -11891,7 +12901,7 @@ PROJBasedOperationNNPtr PROJBasedOperation::create( auto method = OperationMethod::create( util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, - "PROJ-based operation method (approximate) : " + + "PROJ-based operation method (approximate): " + projString), std::vector<GeneralOperationParameterNNPtr>{}); auto op = PROJBasedOperation::nn_make_shared<PROJBasedOperation>(method); @@ -11903,6 +12913,7 @@ PROJBasedOperationNNPtr PROJBasedOperation::create( op->setAccuracies(accuracies); op->projStringExportable_ = projExportable.as_nullable(); op->inverse_ = inverse; + op->setHasBallparkTransformation(hasBallparkTransformation); return op; } @@ -11916,7 +12927,7 @@ CoordinateOperationNNPtr PROJBasedOperation::inverse() const { createPropertiesForInverse(this, false, false), NN_NO_CHECK(projStringExportable_), !inverse_, NN_NO_CHECK(targetCRS()), NN_NO_CHECK(sourceCRS()), - coordinateOperationAccuracies())); + coordinateOperationAccuracies(), hasBallparkTransformation())); } auto formatter = io::PROJStringFormatter::create(); @@ -11929,11 +12940,11 @@ CoordinateOperationNNPtr PROJBasedOperation::inverse() const { } formatter->stopInversion(); - return util::nn_static_pointer_cast<CoordinateOperation>( - PROJBasedOperation::create( - createPropertiesForInverse(this, false, false), - formatter->toString(), targetCRS(), sourceCRS(), - coordinateOperationAccuracies())); + auto op = PROJBasedOperation::create( + createPropertiesForInverse(this, false, false), formatter->toString(), + targetCRS(), sourceCRS(), coordinateOperationAccuracies()); + op->setHasBallparkTransformation(hasBallparkTransformation()); + return util::nn_static_pointer_cast<CoordinateOperation>(op); } // --------------------------------------------------------------------------- @@ -11987,6 +12998,15 @@ void PROJBasedOperation::_exportToPROJString( // --------------------------------------------------------------------------- +CoordinateOperationNNPtr PROJBasedOperation::_shallowClone() const { + auto op = PROJBasedOperation::nn_make_shared<PROJBasedOperation>(*this); + op->assignSelf(op); + op->setCRSs(this, false); + return util::nn_static_pointer_cast<CoordinateOperation>(op); +} + +// --------------------------------------------------------------------------- + std::set<GridDescription> PROJBasedOperation::gridsNeeded( const io::DatabaseContextPtr &databaseContext) const { std::set<GridDescription> res; diff --git a/src/iso19111/coordinatesystem.cpp b/src/iso19111/coordinatesystem.cpp index efba8c05..ef9cac93 100644 --- a/src/iso19111/coordinatesystem.cpp +++ b/src/iso19111/coordinatesystem.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * * Project: PROJ - * Purpose: ISO19111:2018 implementation + * Purpose: ISO19111:2019 implementation * Author: Even Rouault <even dot rouault at spatialys dot com> * ****************************************************************************** @@ -483,7 +483,7 @@ void CoordinateSystem::_exportToWKT( const auto &l_axisList = axisList(); if (isWKT2) { - formatter->startNode(io::WKTConstants::CS, !identifiers().empty()); + formatter->startNode(io::WKTConstants::CS_, !identifiers().empty()); formatter->add(getWKT2Type(formatter->use2018Keywords())); formatter->add(static_cast<int>(l_axisList.size())); formatter->endNode(); diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index 01a588e3..476bc72b 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * * Project: PROJ - * Purpose: ISO19111:2018 implementation + * Purpose: ISO19111:2019 implementation * Author: Even Rouault <even dot rouault at spatialys dot com> * ****************************************************************************** @@ -453,7 +453,7 @@ CRSNNPtr CRS::createBoundCRSToWGS84IfPossible( auto transf = util::nn_dynamic_pointer_cast<operation::Transformation>( op); - if (transf && !starts_with(transf->nameStr(), "Null geo")) { + if (transf && !starts_with(transf->nameStr(), "Ballpark geo")) { try { transf->getTOWGS84Parameters(); } catch (const std::exception &) { @@ -486,7 +486,7 @@ CRSNNPtr CRS::createBoundCRSToWGS84IfPossible( operation::Transformation>(subops[1]); if (transf && !starts_with(transf->nameStr(), - "Null geo")) { + "Ballpark geo")) { try { transf->getTOWGS84Parameters(); } catch (const std::exception &) { @@ -591,6 +591,104 @@ CRSNNPtr CRS::alterId(const std::string &authName, // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress + +static bool isAxisListNorthEast( + const std::vector<cs::CoordinateSystemAxisNNPtr> &axisList) { + const auto &dir0 = axisList[0]->direction(); + const auto &dir1 = axisList[1]->direction(); + return (&dir0 == &cs::AxisDirection::NORTH && + &dir1 == &cs::AxisDirection::EAST); +} +// --------------------------------------------------------------------------- + +bool CRS::mustAxisOrderBeSwitchedForVisualization() const { + + const CompoundCRS *compoundCRS = dynamic_cast<const CompoundCRS *>(this); + if (compoundCRS) { + const auto &comps = compoundCRS->componentReferenceSystems(); + if (!comps.empty()) { + return comps[0]->mustAxisOrderBeSwitchedForVisualization(); + } + } + + const GeographicCRS *geogCRS = dynamic_cast<const GeographicCRS *>(this); + if (geogCRS) { + return isAxisListNorthEast(geogCRS->coordinateSystem()->axisList()); + } + + const ProjectedCRS *projCRS = dynamic_cast<const ProjectedCRS *>(this); + if (projCRS) { + return isAxisListNorthEast(projCRS->coordinateSystem()->axisList()); + } + + return false; +} + +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress + +CRSNNPtr CRS::normalizeForVisualization() const { + auto props = util::PropertyMap().set( + common::IdentifiedObject::NAME_KEY, + nameStr() + " (with axis order normalized for visualization)"); + + const CompoundCRS *compoundCRS = dynamic_cast<const CompoundCRS *>(this); + if (compoundCRS) { + const auto &comps = compoundCRS->componentReferenceSystems(); + if (!comps.empty()) { + std::vector<CRSNNPtr> newComps; + newComps.emplace_back(comps[0]->normalizeForVisualization()); + for (size_t i = 1; i < comps.size(); i++) { + newComps.emplace_back(comps[i]); + } + return util::nn_static_pointer_cast<CRS>( + CompoundCRS::create(props, newComps)); + } + } + + const GeographicCRS *geogCRS = dynamic_cast<const GeographicCRS *>(this); + if (geogCRS) { + const auto &axisList = geogCRS->coordinateSystem()->axisList(); + if (isAxisListNorthEast(axisList)) { + auto cs = axisList.size() == 2 + ? cs::EllipsoidalCS::create(util::PropertyMap(), + axisList[1], axisList[0]) + : cs::EllipsoidalCS::create(util::PropertyMap(), + axisList[1], axisList[0], + axisList[2]); + return util::nn_static_pointer_cast<CRS>(GeographicCRS::create( + props, geogCRS->datum(), geogCRS->datumEnsemble(), cs)); + } + } + + const ProjectedCRS *projCRS = dynamic_cast<const ProjectedCRS *>(this); + if (projCRS) { + const auto &axisList = projCRS->coordinateSystem()->axisList(); + if (isAxisListNorthEast(axisList)) { + auto cs = + axisList.size() == 2 + ? cs::CartesianCS::create(util::PropertyMap(), axisList[1], + axisList[0]) + : cs::CartesianCS::create(util::PropertyMap(), axisList[1], + axisList[0], axisList[2]); + return util::nn_static_pointer_cast<CRS>( + ProjectedCRS::create(props, projCRS->baseCRS(), + projCRS->derivingConversionRef(), cs)); + } + } + + return NN_NO_CHECK( + std::static_pointer_cast<CRS>(shared_from_this().as_nullable())); +} + +//! @endcond + +// --------------------------------------------------------------------------- + /** \brief Identify the CRS with reference CRSs. * * The candidate CRSs are either hard-coded, or looked in the database when @@ -1289,6 +1387,36 @@ GeodeticCRSNNPtr GeodeticCRS::createEPSG_4978() { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress + +static bool hasCodeCompatibleOfAuthorityFactory( + const common::IdentifiedObject *obj, + const io::AuthorityFactoryPtr &authorityFactory) { + const auto &ids = obj->identifiers(); + if (!ids.empty() && authorityFactory->getAuthority().empty()) { + return true; + } + for (const auto &id : ids) { + if (*(id->codeSpace()) == authorityFactory->getAuthority()) { + return true; + } + } + return false; +} + +static bool hasCodeCompatibleOfAuthorityFactory( + const metadata::IdentifierNNPtr &id, + const io::AuthorityFactoryPtr &authorityFactory) { + if (authorityFactory->getAuthority().empty()) { + return true; + } + return *(id->codeSpace()) == authorityFactory->getAuthority(); +} + +//! @endcond + +// --------------------------------------------------------------------------- + /** \brief Identify the CRS with reference CRSs. * * The candidate CRSs are either hard-coded, or looked in the database when @@ -1432,19 +1560,22 @@ GeodeticCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { searchByEllipsoid(); } } - } else if (!identifiers().empty()) { + } else if (hasCodeCompatibleOfAuthorityFactory(this, + authorityFactory)) { // If the CRS has already an id, check in the database for the // official object, and verify that they are equivalent. for (const auto &id : identifiers()) { - try { - auto crs = io::AuthorityFactory::create( - authorityFactory->databaseContext(), - *id->codeSpace()) - ->createGeodeticCRS(id->code()); - bool match = _isEquivalentTo(crs.get(), crsCriterion); - res.emplace_back(crs, match ? 100 : 25); - return res; - } catch (const std::exception &) { + if (hasCodeCompatibleOfAuthorityFactory(id, authorityFactory)) { + try { + auto crs = io::AuthorityFactory::create( + authorityFactory->databaseContext(), + *id->codeSpace()) + ->createGeodeticCRS(id->code()); + bool match = _isEquivalentTo(crs.get(), crsCriterion); + res.emplace_back(crs, match ? 100 : 25); + return res; + } catch (const std::exception &) { + } } } } else { @@ -1892,9 +2023,7 @@ void GeographicCRS::addAngularUnitConvertAndAxisSwap( if (order[0] && order[1] && (order[0] != one || order[1] != two)) { formatter->addStep("axisswap"); char orderStr[10]; - strcpy(orderStr, order[0]); - strcat(orderStr, ","); - strcat(orderStr, order[1]); + sprintf(orderStr, "%.2s,%.2s", order[0], order[1]); formatter->addParam("order", orderStr); } } @@ -2096,7 +2225,6 @@ void VerticalCRS::addLinearUnitConvert( auto &axisList = coordinateSystem()->axisList(); if (!axisList.empty()) { - auto projUnit = axisList[0]->unit().exportToPROJString(); if (axisList[0]->unit().conversionToSI() != 1.0) { formatter->addStep("unitconvert"); formatter->addParam("z_in", "m"); @@ -2204,20 +2332,23 @@ VerticalCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { const bool unsignificantName = thisName.empty() || ci_equal(thisName, "unknown") || ci_equal(thisName, "unnamed"); - if (!identifiers().empty()) { + if (hasCodeCompatibleOfAuthorityFactory(this, authorityFactory)) { // If the CRS has already an id, check in the database for the // official object, and verify that they are equivalent. for (const auto &id : identifiers()) { - try { - auto crs = io::AuthorityFactory::create( - authorityFactory->databaseContext(), - *id->codeSpace()) - ->createVerticalCRS(id->code()); - bool match = _isEquivalentTo( - crs.get(), util::IComparable::Criterion::EQUIVALENT); - res.emplace_back(crs, match ? 100 : 25); - return res; - } catch (const std::exception &) { + if (hasCodeCompatibleOfAuthorityFactory(id, authorityFactory)) { + try { + auto crs = io::AuthorityFactory::create( + authorityFactory->databaseContext(), + *id->codeSpace()) + ->createVerticalCRS(id->code()); + bool match = _isEquivalentTo( + crs.get(), + util::IComparable::Criterion::EQUIVALENT); + res.emplace_back(crs, match ? 100 : 25); + return res; + } catch (const std::exception &) { + } } } } else if (!unsignificantName) { @@ -2422,16 +2553,21 @@ void DerivedCRS::setDerivingConversionCRS() { // --------------------------------------------------------------------------- -void DerivedCRS::baseExportToWKT(io::WKTFormatter *&formatter, +void DerivedCRS::baseExportToWKT(io::WKTFormatter *formatter, const std::string &keyword, const std::string &baseKeyword) const { formatter->startNode(keyword, !identifiers().empty()); formatter->addQuotedString(nameStr()); const auto &l_baseCRS = d->baseCRS_; - formatter->startNode(baseKeyword, !l_baseCRS->identifiers().empty()); + formatter->startNode(baseKeyword, formatter->use2018Keywords() && + !l_baseCRS->identifiers().empty()); formatter->addQuotedString(l_baseCRS->nameStr()); l_baseCRS->exportDatumOrDatumEnsembleToWkt(formatter); + if (formatter->use2018Keywords() && + !(formatter->idOnTopLevelOnly() && formatter->topLevelHasId())) { + l_baseCRS->formatID(formatter); + } formatter->endNode(); formatter->setUseDerivingConversion(true); @@ -2659,7 +2795,7 @@ void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const { dynamic_cast<const GeographicCRS *>(l_baseCRS.get())) ? io::WKTConstants::BASEGEOGCRS : io::WKTConstants::BASEGEODCRS, - !l_baseCRS->identifiers().empty()); + formatter->use2018Keywords() && !l_baseCRS->identifiers().empty()); formatter->addQuotedString(l_baseCRS->nameStr()); l_baseCRS->exportDatumOrDatumEnsembleToWkt(formatter); // insert ellipsoidal cs unit when the units of the map @@ -2670,6 +2806,10 @@ void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const { geodeticCRSAxisList[0]->unit()._exportToWKT(formatter); } l_baseCRS->primeMeridian()->_exportToWKT(formatter); + if (formatter->use2018Keywords() && + !(formatter->idOnTopLevelOnly() && formatter->topLevelHasId())) { + l_baseCRS->formatID(formatter); + } formatter->endNode(); } else { const auto oldAxisOutputRule = formatter->outputAxis(); @@ -2843,9 +2983,7 @@ void ProjectedCRS::addUnitConvertAndAxisSwap(io::PROJStringFormatter *formatter, if (order[0] && order[1]) { formatter->addStep("axisswap"); char orderStr[10]; - strcpy(orderStr, order[0]); - strcat(orderStr, ","); - strcat(orderStr, order[1]); + sprintf(orderStr, "%.2s,%.2s", order[0], order[1]); formatter->addParam("order", orderStr); } } else { @@ -2998,21 +3136,24 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { ci_equal(thisName, "unnamed"); bool foundEquivalentName = false; - if (!identifiers().empty()) { + if (hasCodeCompatibleOfAuthorityFactory(this, authorityFactory)) { // If the CRS has already an id, check in the database for the // official object, and verify that they are equivalent. for (const auto &id : identifiers()) { - try { - auto crs = io::AuthorityFactory::create( - authorityFactory->databaseContext(), - *id->codeSpace()) - ->createProjectedCRS(id->code()); - bool match = _isEquivalentTo( - crs.get(), util::IComparable::Criterion:: - EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS); - res.emplace_back(crs, match ? 100 : 25); - return res; - } catch (const std::exception &) { + if (hasCodeCompatibleOfAuthorityFactory(id, authorityFactory)) { + try { + auto crs = io::AuthorityFactory::create( + authorityFactory->databaseContext(), + *id->codeSpace()) + ->createProjectedCRS(id->code()); + bool match = _isEquivalentTo( + crs.get(), + util::IComparable::Criterion:: + EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS); + res.emplace_back(crs, match ? 100 : 25); + return res; + } catch (const std::exception &) { + } } } } else if (!unsignificantName) { @@ -3087,8 +3228,8 @@ ProjectedCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { // Sort results res.sort(lambdaSort); - if (identifiers().empty() && !foundEquivalentName && - (res.empty() || res.front().second < 50)) { + if (!hasCodeCompatibleOfAuthorityFactory(this, authorityFactory) && + !foundEquivalentName && (res.empty() || res.front().second < 50)) { std::set<std::pair<std::string, std::string>> alreadyKnown; for (const auto &pair : res) { const auto &ids = pair.first->identifiers(); @@ -3346,20 +3487,23 @@ CompoundCRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const { ci_equal(thisName, "unnamed"); bool foundEquivalentName = false; - if (!identifiers().empty()) { + if (hasCodeCompatibleOfAuthorityFactory(this, authorityFactory)) { // If the CRS has already an id, check in the database for the // official object, and verify that they are equivalent. for (const auto &id : identifiers()) { - try { - auto crs = io::AuthorityFactory::create( - authorityFactory->databaseContext(), - *id->codeSpace()) - ->createCompoundCRS(id->code()); - bool match = _isEquivalentTo( - crs.get(), util::IComparable::Criterion::EQUIVALENT); - res.emplace_back(crs, match ? 100 : 25); - return res; - } catch (const std::exception &) { + if (hasCodeCompatibleOfAuthorityFactory(id, authorityFactory)) { + try { + auto crs = io::AuthorityFactory::create( + authorityFactory->databaseContext(), + *id->codeSpace()) + ->createCompoundCRS(id->code()); + bool match = _isEquivalentTo( + crs.get(), + util::IComparable::Criterion::EQUIVALENT); + res.emplace_back(crs, match ? 100 : 25); + return res; + } catch (const std::exception &) { + } } } } else if (!unsignificantName) { @@ -3855,7 +3999,7 @@ BoundCRS::_identify(const io::AuthorityFactoryPtr &authorityFactory) const { for (const auto &op : ops) { std::string opTransfPROJString; bool opTransfPROJStringValid = false; - if (op->nameStr().find("Null geographic") == 0) { + if (op->nameStr().find("Ballpark geographic") == 0) { if (isTOWGS84Compatible()) { auto params = transformation()->getTOWGS84Parameters(); @@ -4849,7 +4993,7 @@ DerivedCRSTemplate<DerivedCRSTraits>::create( // --------------------------------------------------------------------------- -static void DerivedCRSTemplateCheckExportToWKT(io::WKTFormatter *&formatter, +static void DerivedCRSTemplateCheckExportToWKT(io::WKTFormatter *formatter, const std::string &crsName, bool wkt2_2018_only) { const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp index 66717f70..bf3092c1 100644 --- a/src/iso19111/datum.cpp +++ b/src/iso19111/datum.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * * Project: PROJ - * Purpose: ISO19111:2018 implementation + * Purpose: ISO19111:2019 implementation * Author: Even Rouault <even dot rouault at spatialys dot com> * ****************************************************************************** @@ -154,7 +154,7 @@ const util::optional<std::string> &Datum::anchorDefinition() const { /** \brief Return the date on which the datum definition was published. * - * \note Departure from \ref ISO_19111_2018 : we return a DateTime instead of + * \note Departure from \ref ISO_19111_2019 : we return a DateTime instead of * a Citation::Date. * * @return the publication date, or empty. @@ -783,7 +783,7 @@ bool Ellipsoid::lookForProjWellKnownEllps(std::string &projEllpsName, if (::fabs(b - b_iter) < 1e-10 * b_iter) { projEllpsName = proj_ellps[i].id; ellpsName = proj_ellps[i].name; - if (ellpsName.find("GRS 1980") == 0) { + if (starts_with(ellpsName, "GRS 1980")) { ellpsName = "GRS 1980"; } return true; @@ -794,7 +794,7 @@ bool Ellipsoid::lookForProjWellKnownEllps(std::string &projEllpsName, if (::fabs(rf - rf_iter) < 1e-10 * rf_iter) { projEllpsName = proj_ellps[i].id; ellpsName = proj_ellps[i].name; - if (ellpsName.find("GRS 1980") == 0) { + if (starts_with(ellpsName, "GRS 1980")) { ellpsName = "GRS 1980"; } return true; @@ -1010,7 +1010,7 @@ GeodeticReferenceFrame::primeMeridian() PROJ_PURE_DEFN { /** \brief Return the Ellipsoid associated with a GeodeticReferenceFrame. * - * \note The \ref ISO_19111_2018 modelling allows (but discourages) a + * \note The \ref ISO_19111_2019 modelling allows (but discourages) a * GeodeticReferenceFrame * to not be associated with a Ellipsoid in the case where it is used by a * geocentric crs::GeodeticCRS. We have made the choice of making the ellipsoid @@ -1223,7 +1223,7 @@ DynamicGeodeticReferenceFrame::frameReferenceEpoch() const { /** \brief Return the name of the deformation model. * - * @note This is an extension to the \ref ISO_19111_2018 modeling, to + * @note This is an extension to the \ref ISO_19111_2019 modeling, to * hold the content of the DYNAMIC.MODEL WKT2 node. * * @return the name of the deformation model. @@ -1660,7 +1660,7 @@ DynamicVerticalReferenceFrame::frameReferenceEpoch() const { /** \brief Return the name of the deformation model. * - * @note This is an extension to the \ref ISO_19111_2018 modeling, to + * @note This is an extension to the \ref ISO_19111_2019 modeling, to * hold the content of the DYNAMIC.MODEL WKT2 node. * * @return the name of the deformation model. diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 81abcdf1..4515188a 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * * Project: PROJ - * Purpose: ISO19111:2018 implementation + * Purpose: ISO19111:2019 implementation * Author: Even Rouault <even dot rouault at spatialys dot com> * ****************************************************************************** @@ -259,7 +259,7 @@ struct DatabaseContext::Private { static void getFromCache(LRUCacheOfObjects &cache, const std::string &code, util::BaseObjectPtr &obj); - void closeDB(); + void closeDB() noexcept; // cppcheck-suppress functionStatic void registerFunctions(); @@ -295,7 +295,7 @@ DatabaseContext::Private::~Private() { // --------------------------------------------------------------------------- -void DatabaseContext::Private::closeDB() { +void DatabaseContext::Private::closeDB() noexcept { if (detach_) { // Workaround a bug visible in SQLite 3.8.1 and 3.8.2 that causes @@ -309,7 +309,10 @@ void DatabaseContext::Private::closeDB() { // https://github.com/mackyle/sqlite/commit/ccf328c4318eacedab9ed08c404bc4f402dcad19 // also seemed to hide the issue. // Detaching a database hides the issue, not sure if it is by chance... - run("DETACH DATABASE db_0"); + try { + run("DETACH DATABASE db_0"); + } catch (...) { + } detach_ = false; } @@ -611,11 +614,16 @@ void DatabaseContext::Private::setHandle(sqlite3 *sqlite_handle) { // --------------------------------------------------------------------------- std::vector<std::string> DatabaseContext::Private::getDatabaseStructure() { - auto sqlRes = run("SELECT sql FROM sqlite_master WHERE type " - "IN ('table', 'trigger', 'view') ORDER BY type"); + const char *sqls[] = { + "SELECT sql FROM sqlite_master WHERE type = 'table'", + "SELECT sql FROM sqlite_master WHERE type = 'view'", + "SELECT sql FROM sqlite_master WHERE type = 'trigger'"}; std::vector<std::string> res; - for (const auto &row : sqlRes) { - res.emplace_back(row[0]); + for (const auto &sql : sqls) { + auto sqlRes = run(sql); + for (const auto &row : sqlRes) { + res.emplace_back(row[0]); + } } return res; } @@ -1024,8 +1032,8 @@ bool DatabaseContext::lookForGridInfo(const std::string &projFilename, info.url = url; info.directDownload = directDownload; info.openLicense = openLicense; - info.gridAvailable = gridAvailable; } + info.gridAvailable = gridAvailable; info.found = ret; d->cache(projFilename, info); return ret; @@ -1359,6 +1367,15 @@ const DatabaseContextNNPtr &AuthorityFactory::databaseContext() const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +AuthorityFactory::CRSInfo::CRSInfo() + : authName{}, code{}, name{}, type{ObjectType::CRS}, deprecated{}, + bbox_valid{}, west_lon_degree{}, south_lat_degree{}, east_lon_degree{}, + north_lat_degree{}, areaName{}, projectionMethodName{} {} +//! @endcond + +// --------------------------------------------------------------------------- + /** \brief Returns an arbitrary object from a code. * * The returned object will typically be an instance of Datum, @@ -1606,10 +1623,12 @@ static double normalizeMeasure(const std::string &uom_code, assert(seconds.size() == precision - 2); normalized_value = (normalized_value < 0 ? -1.0 : 1.0) * - (int(std::fabs(normalized_value)) + c_locale_stod(minutes) / 60. + + (std::floor(std::fabs(normalized_value)) + + c_locale_stod(minutes) / 60. + (c_locale_stod(seconds) / std::pow(10, seconds.size() - 2)) / 3600.); normalized_uom_code = common::UnitOfMeasure::DEGREE.code(); + /* coverity[overflow_sink] */ return normalized_value; } else { normalized_uom_code = uom_code; @@ -2394,6 +2413,11 @@ AuthorityFactory::createProjectedCRS(const std::string &code) const { auto conv = d->createFactory(conversion_auth_name) ->createConversion(conversion_code); + if (conv->nameStr() == "unnamed") { + conv = conv->shallowClone(); + conv->setProperties(util::PropertyMap().set( + common::IdentifiedObject::NAME_KEY, name)); + } auto cartesianCS = util::nn_dynamic_pointer_cast<cs::CartesianCS>(cs); if (cartesianCS) { @@ -2470,6 +2494,8 @@ crs::CRSNNPtr AuthorityFactory::createCoordinateReferenceSystem( return createCoordinateReferenceSystem(code, true); } +//! @cond Doxygen_Suppress + crs::CRSNNPtr AuthorityFactory::createCoordinateReferenceSystem(const std::string &code, bool allowCompound) const { @@ -2499,6 +2525,9 @@ AuthorityFactory::createCoordinateReferenceSystem(const std::string &code, } throw FactoryException("unhandled CRS type: " + type); } + +//! @endcond + // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress @@ -2588,7 +2617,7 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( "rate_scale_difference, rate_scale_difference_uom_auth_name, " "rate_scale_difference_uom_code, epoch, epoch_uom_auth_name, " "epoch_uom_code, px, py, pz, pivot_uom_auth_name, pivot_uom_code, " - "deprecated FROM " + "operation_version, deprecated FROM " "helmert_transformation WHERE auth_name = ? AND code = ?", code); if (res.empty()) { @@ -2649,6 +2678,7 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( const auto &pivot_uom_auth_name = row[idx++]; const auto &pivot_uom_code = row[idx++]; + const auto &operation_version = row[idx++]; const auto &deprecated_str = row[idx++]; const bool deprecated = deprecated_str == "1"; assert(idx == row.size()); @@ -2789,6 +2819,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( auto props = d->createProperties(code, name, deprecated, area_of_use_auth_name, area_of_use_code); + if (!operation_version.empty()) { + props.set(operation::CoordinateOperation::OPERATION_VERSION_KEY, + operation_version); + } auto propsMethod = util::PropertyMap() @@ -2819,8 +2853,8 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( "grid_name, " "grid2_param_auth_name, grid2_param_code, grid2_param_name, " "grid2_name, " - "interpolation_crs_auth_name, interpolation_crs_code, deprecated " - "FROM " + "interpolation_crs_auth_name, interpolation_crs_code, " + "operation_version, deprecated FROM " "grid_transformation WHERE auth_name = ? AND code = ?", code); if (res.empty()) { @@ -2852,7 +2886,7 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( const auto &grid2_name = row[idx++]; const auto &interpolation_crs_auth_name = row[idx++]; const auto &interpolation_crs_code = row[idx++]; - + const auto &operation_version = row[idx++]; const auto &deprecated_str = row[idx++]; const bool deprecated = deprecated_str == "1"; assert(idx == row.size()); @@ -2898,6 +2932,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( auto props = d->createProperties(code, name, deprecated, area_of_use_auth_name, area_of_use_code); + if (!operation_version.empty()) { + props.set(operation::CoordinateOperation::OPERATION_VERSION_KEY, + operation_version); + } auto propsMethod = util::PropertyMap() .set(metadata::Identifier::CODESPACE_KEY, method_auth_name) @@ -2939,8 +2977,8 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( buffer << ", param" << i << "_uom_auth_name"; buffer << ", param" << i << "_uom_code"; } - buffer << ", deprecated FROM other_transformation WHERE auth_name = ? " - "AND code = ?"; + buffer << ", operation_version, deprecated FROM other_transformation " + "WHERE auth_name = ? AND code = ?"; auto res = d->runWithCodeParam(buffer.str(), code); if (res.empty()) { @@ -2993,6 +3031,7 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( } idx = base_param_idx + 6 * N_MAX_PARAMS; + const auto &operation_version = row[idx++]; const auto &deprecated_str = row[idx++]; const bool deprecated = deprecated_str == "1"; assert(idx == row.size()); @@ -3007,6 +3046,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( auto props = d->createProperties(code, name, deprecated, area_of_use_auth_name, area_of_use_code); + if (!operation_version.empty()) { + props.set(operation::CoordinateOperation::OPERATION_VERSION_KEY, + operation_version); + } std::vector<metadata::PositionalAccuracyNNPtr> accuracies; if (!accuracy.empty()) { @@ -3060,7 +3103,7 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( "target_crs_auth_name, target_crs_code, " "area_of_use_auth_name, area_of_use_code, accuracy, " "step1_auth_name, step1_code, step2_auth_name, step2_code, " - "step3_auth_name, step3_code, deprecated FROM " + "step3_auth_name, step3_code, operation_version, deprecated FROM " "concatenated_operation WHERE auth_name = ? AND code = ?", code); if (res.empty()) { @@ -3085,6 +3128,7 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( const auto &step2_code = row[idx++]; const auto &step3_auth_name = row[idx++]; const auto &step3_code = row[idx++]; + const auto &operation_version = row[idx++]; const auto &deprecated_str = row[idx++]; const bool deprecated = deprecated_str == "1"; @@ -3118,6 +3162,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation( auto props = d->createProperties(code, name, deprecated, area_of_use_auth_name, area_of_use_code); + if (!operation_version.empty()) { + props.set(operation::CoordinateOperation::OPERATION_VERSION_KEY, + operation_version); + } std::vector<metadata::PositionalAccuracyNNPtr> accuracies; if (!accuracy.empty()) { @@ -3873,7 +3921,7 @@ AuthorityFactory::getDescriptionText(const std::string &code) const { /** \brief Return a list of information on CRS objects * * This is functionnaly equivalent of listing the codes from an authority, - * instanciating + * instantiating * a CRS object for each of them and getting the information from this CRS * object, but this implementation has much less overhead. * @@ -3896,13 +3944,16 @@ std::list<AuthorityFactory::CRSInfo> AuthorityFactory::getCRSInfoList() const { sql += "SELECT c.auth_name, c.code, c.name, 'projected', " "c.deprecated, " "a.west_lon, a.south_lat, a.east_lon, a.north_lat, " - "a.name, conv.method_name FROM projected_crs c " + "a.name, cm.name AS conversion_method_name FROM projected_crs c " "JOIN area a ON " "c.area_of_use_auth_name = a.auth_name AND " "c.area_of_use_code = a.code " - "LEFT JOIN conversion conv ON " + "LEFT JOIN conversion_table conv ON " "c.conversion_auth_name = conv.auth_name AND " - "c.conversion_code = conv.code"; + "c.conversion_code = conv.code " + "LEFT JOIN conversion_method cm ON " + "conv.method_auth_name = cm.auth_name AND " + "conv.method_code = cm.code"; if (d->hasAuthorityRestriction()) { sql += " WHERE c.auth_name = ?"; params.emplace_back(d->authority()); @@ -4625,9 +4676,9 @@ AuthorityFactory::createProjectedCRSFromExisting( std::string sql( "SELECT projected_crs.auth_name, projected_crs.code FROM projected_crs " - "JOIN conversion ON " - "projected_crs.conversion_auth_name = conversion.auth_name AND " - "projected_crs.conversion_code = conversion.code WHERE " + "JOIN conversion_table conv ON " + "projected_crs.conversion_auth_name = conv.auth_name AND " + "projected_crs.conversion_code = conv.code WHERE " "projected_crs.deprecated = 0 AND "); ListOfParams params; if (!candidatesGeodCRS.empty()) { @@ -4635,8 +4686,8 @@ AuthorityFactory::createProjectedCRSFromExisting( "projected_crs.geodetic_crs_"); sql += " AND "; } - sql += "conversion.method_auth_name = 'EPSG' AND " - "conversion.method_code = ?"; + sql += "conv.method_auth_name = 'EPSG' AND " + "conv.method_code = ?"; params.emplace_back(toString(methodEPSGCode)); if (d->hasAuthorityRestriction()) { sql += " AND projected_crs.auth_name = ?"; @@ -4663,11 +4714,11 @@ AuthorityFactory::createProjectedCRSFromExisting( if (unit == common::UnitOfMeasure::DEGREE && geogCRS->coordinateSystem()->axisList()[0]->unit() == unit) { const auto iParamAsStr(toString(iParam)); - sql += " AND conversion.param"; + sql += " AND conv.param"; sql += iParamAsStr; - sql += "_code = ? AND conversion.param"; + sql += "_code = ? AND conv.param"; sql += iParamAsStr; - sql += "_auth_name = 'EPSG' AND conversion.param"; + sql += "_auth_name = 'EPSG' AND conv.param"; sql += iParamAsStr; sql += "_value BETWEEN ? AND ?"; // As angles might be expressed with the odd unit EPSG:9110 diff --git a/src/iso19111/internal.cpp b/src/iso19111/internal.cpp index 0c330d30..4810202d 100644 --- a/src/iso19111/internal.cpp +++ b/src/iso19111/internal.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * * Project: PROJ - * Purpose: ISO19111:2018 implementation + * Purpose: ISO19111:2019 implementation * Author: Even Rouault <even dot rouault at spatialys dot com> * ****************************************************************************** @@ -298,6 +298,21 @@ std::vector<std::string> split(const std::string &str, char separator) { // --------------------------------------------------------------------------- +std::vector<std::string> split(const std::string &str, + const std::string &separator) { + std::vector<std::string> res; + size_t lastPos = 0; + size_t newPos = 0; + while ((newPos = str.find(separator, lastPos)) != std::string::npos) { + res.push_back(str.substr(lastPos, newPos - lastPos)); + lastPos = newPos + separator.size(); + } + res.push_back(str.substr(lastPos)); + return res; +} + +// --------------------------------------------------------------------------- + #ifdef _WIN32 // For some reason, sqlite3_snprintf() in the sqlite3 builds used on AppVeyor diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index e14239b0..7329758a 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * * Project: PROJ - * Purpose: ISO19111:2018 implementation + * Purpose: ISO19111:2019 implementation * Author: Even Rouault <even dot rouault at spatialys dot com> * ****************************************************************************** @@ -141,6 +141,7 @@ struct WKTFormatter::Private { std::vector<bool> stackHasChild_{}; std::vector<bool> stackHasId_{false}; std::vector<bool> stackEmptyKeyword_{}; + std::vector<bool> stackDisableUsage_{}; std::vector<bool> outputUnitStack_{true}; std::vector<bool> outputIdStack_{true}; std::vector<UnitOfMeasureNNPtr> axisLinearUnitStack_{ @@ -272,6 +273,11 @@ const std::string &WKTFormatter::toString() const { if (d->outputUnitStack_.size() != 1) throw FormattingException( "Unbalanced pushOutputUnit() / popOutputUnit()"); + if (d->stackHasId_.size() != 1) + throw FormattingException("Unbalanced pushHasId() / popHasId()"); + if (!d->stackDisableUsage_.empty()) + throw FormattingException( + "Unbalanced pushDisableUsage() / popDisableUsage()"); return d->result_; } @@ -556,6 +562,28 @@ bool WKTFormatter::outputId() const { // --------------------------------------------------------------------------- +void WKTFormatter::pushHasId(bool hasId) { d->stackHasId_.push_back(hasId); } + +// --------------------------------------------------------------------------- + +void WKTFormatter::popHasId() { d->stackHasId_.pop_back(); } + +// --------------------------------------------------------------------------- + +void WKTFormatter::pushDisableUsage() { d->stackDisableUsage_.push_back(true); } + +// --------------------------------------------------------------------------- + +void WKTFormatter::popDisableUsage() { d->stackDisableUsage_.pop_back(); } + +// --------------------------------------------------------------------------- + +bool WKTFormatter::outputUsage() const { + return outputId() && d->stackDisableUsage_.empty(); +} + +// --------------------------------------------------------------------------- + void WKTFormatter::pushAxisLinearUnit(const UnitOfMeasureNNPtr &unit) { d->axisLinearUnitStack_.push_back(unit); } @@ -634,6 +662,18 @@ bool WKTFormatter::primeMeridianInDegree() const { // --------------------------------------------------------------------------- +bool WKTFormatter::idOnTopLevelOnly() const { + return d->params_.idOnTopLevelOnly_; +} + +// --------------------------------------------------------------------------- + +bool WKTFormatter::topLevelHasId() const { + return d->stackHasId_.size() >= 2 && d->stackHasId_[1]; +} + +// --------------------------------------------------------------------------- + WKTFormatter::Version WKTFormatter::version() const { return d->params_.version_; } @@ -717,13 +757,22 @@ const std::string &WKTFormatter::getHDatumExtension() const { // --------------------------------------------------------------------------- std::string WKTFormatter::morphNameToESRI(const std::string &name) { + + for (const auto *suffix : {"(m)", "(ftUS)", "(E-N)", "(N-E)"}) { + if (ends_with(name, suffix)) { + return morphNameToESRI( + name.substr(0, name.size() - strlen(suffix))) + + suffix; + } + } + std::string ret; bool insertUnderscore = false; // Replace any special character by underscore, except at the beginning // and of the name where those characters are removed. for (char ch : name) { - if (ch == '+' || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || - (ch >= 'A' && ch <= 'Z')) { + if (ch == '+' || ch == '-' || (ch >= '0' && ch <= '9') || + (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { if (insertUnderscore && !ret.empty()) { ret += '_'; } @@ -973,7 +1022,7 @@ const std::vector<WKTNodeNNPtr> &WKTNode::children() const { //! @cond Doxygen_Suppress static size_t skipSpace(const std::string &str, size_t start) { size_t i = start; - while (i < str.size() && ::isspace(str[i])) { + while (i < str.size() && ::isspace(static_cast<unsigned char>(str[i]))) { ++i; } return i; @@ -1002,8 +1051,9 @@ WKTNodeNNPtr WKTNode::createFrom(const std::string &wkt, size_t indexStart, bool inString = false; for (; i < wkt.size() && - (inString || (wkt[i] != '[' && wkt[i] != '(' && wkt[i] != ',' && - wkt[i] != ']' && wkt[i] != ')' && !::isspace(wkt[i]))); + (inString || + (wkt[i] != '[' && wkt[i] != '(' && wkt[i] != ',' && wkt[i] != ']' && + wkt[i] != ')' && !::isspace(static_cast<unsigned char>(wkt[i])))); ++i) { if (wkt[i] == '"') { if (!inString) { @@ -1185,7 +1235,7 @@ struct WKTParser::Private { buildPrimeMeridian(const WKTNodeNNPtr &node, const UnitOfMeasure &defaultAngularUnit); - optional<std::string> getAnchor(const WKTNodeNNPtr &node); + static optional<std::string> getAnchor(const WKTNodeNNPtr &node); static void parseDynamic(const WKTNodeNNPtr &dynamicNode, double &frameReferenceEpoch, @@ -1301,7 +1351,7 @@ struct WKTParser::Private { CRSPtr buildCRS(const WKTNodeNNPtr &node); - CoordinateOperationNNPtr buildCoordinateOperation(const WKTNodeNNPtr &node); + TransformationNNPtr buildCoordinateOperation(const WKTNodeNNPtr &node); ConcatenatedOperationNNPtr buildConcatenatedOperation(const WKTNodeNNPtr &node); @@ -1580,6 +1630,17 @@ PropertyMap &WKTParser::Private::buildProperties(const WKTNodeNNPtr &node, } } + auto &versionNode = nodeP->lookForChild(WKTConstants::VERSION); + if (!isNull(versionNode)) { + const auto &versionChildren = versionNode->GP()->children(); + if (versionChildren.size() == 1) { + properties->set(CoordinateOperation::OPERATION_VERSION_KEY, + stripQuotes(versionChildren[0])); + } else { + ThrowNotRequiredNumberOfChildren(versionNode->GP()->value()); + } + } + return *properties; } @@ -2556,13 +2617,13 @@ WKTParser::Private::buildGeodeticCRS(const WKTNodeNNPtr &node) { auto &dynamicNode = nodeP->lookForChild(WKTConstants::DYNAMIC); - auto &csNode = nodeP->lookForChild(WKTConstants::CS); + auto &csNode = nodeP->lookForChild(WKTConstants::CS_); const auto &nodeName = nodeP->value(); if (isNull(csNode) && !ci_equal(nodeName, WKTConstants::GEOGCS) && !ci_equal(nodeName, WKTConstants::GEOCCS) && !ci_equal(nodeName, WKTConstants::BASEGEODCRS) && !ci_equal(nodeName, WKTConstants::BASEGEOGCRS)) { - ThrowMissing(WKTConstants::CS); + ThrowMissing(WKTConstants::CS_); } auto &primeMeridianNode = @@ -2712,9 +2773,9 @@ CRSNNPtr WKTParser::Private::buildDerivedGeodeticCRS(const WKTNodeNNPtr &node) { auto derivingConversion = buildConversion( derivingConversionNode, UnitOfMeasure::NONE, UnitOfMeasure::NONE); - auto &csNode = nodeP->lookForChild(WKTConstants::CS); + auto &csNode = nodeP->lookForChild(WKTConstants::CS_); if (isNull(csNode)) { - ThrowMissing(WKTConstants::CS); + ThrowMissing(WKTConstants::CS_); } auto cs = buildCS(csNode, node, UnitOfMeasure::NONE); @@ -2888,7 +2949,7 @@ WKTParser::Private::buildConversion(const WKTNodeNNPtr &node, // --------------------------------------------------------------------------- -CoordinateOperationNNPtr +TransformationNNPtr WKTParser::Private::buildCoordinateOperation(const WKTNodeNNPtr &node) { const auto *nodeP = node->GP(); auto &methodNode = nodeP->lookForChild(WKTConstants::METHOD); @@ -2939,11 +3000,10 @@ WKTParser::Private::buildCoordinateOperation(const WKTNodeNNPtr &node) { stripQuotes(accuracyNode->GP()->children()[0]))); } - return util::nn_static_pointer_cast<CoordinateOperation>( - Transformation::create(buildProperties(node), NN_NO_CHECK(sourceCRS), - NN_NO_CHECK(targetCRS), interpolationCRS, - buildProperties(methodNode), parameters, values, - accuracies)); + return Transformation::create(buildProperties(node), NN_NO_CHECK(sourceCRS), + NN_NO_CHECK(targetCRS), interpolationCRS, + buildProperties(methodNode), parameters, + values, accuracies); } // --------------------------------------------------------------------------- @@ -3116,7 +3176,6 @@ ConversionNNPtr WKTParser::Private::buildProjectionFromESRI( } const auto *wkt2_mapping = getMapping(esriMapping->wkt2_name); - assert(wkt2_mapping); if (ci_equal(esriProjectionName, "Stereographic")) { try { if (std::fabs(io::asDouble( @@ -3127,6 +3186,7 @@ ConversionNNPtr WKTParser::Private::buildProjectionFromESRI( } catch (const std::exception &) { } } + assert(wkt2_mapping); PropertyMap propertiesMethod; propertiesMethod.set(IdentifiedObject::NAME_KEY, wkt2_mapping->wkt2_name); @@ -3205,7 +3265,10 @@ ConversionNNPtr WKTParser::Private::buildProjectionFromESRI( } return Conversion::create( - PropertyMap().set(IdentifiedObject::NAME_KEY, "unnamed"), + PropertyMap().set(IdentifiedObject::NAME_KEY, + esriProjectionName == "Gauss_Kruger" + ? "unnnamed (Gauss Kruger)" + : "unnamed"), propertiesMethod, parameters, values) ->identify(); } @@ -3539,11 +3602,11 @@ WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) { ? buildConversion(conversionNode, linearUnit, angularUnit) : buildProjection(node, projectionNode, linearUnit, angularUnit); - auto &csNode = nodeP->lookForChild(WKTConstants::CS); + auto &csNode = nodeP->lookForChild(WKTConstants::CS_); const auto &nodeValue = nodeP->value(); if (isNull(csNode) && !ci_equal(nodeValue, WKTConstants::PROJCS) && !ci_equal(nodeValue, WKTConstants::BASEPROJCRS)) { - ThrowMissing(WKTConstants::CS); + ThrowMissing(WKTConstants::CS_); } auto cs = buildCS(csNode, node, UnitOfMeasure::NONE); auto cartesianCS = nn_dynamic_pointer_cast<CartesianCS>(cs); @@ -3726,11 +3789,11 @@ CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) { ? buildDatumEnsemble(ensembleNode, nullptr, false).as_nullable() : nullptr; - auto &csNode = nodeP->lookForChild(WKTConstants::CS); + auto &csNode = nodeP->lookForChild(WKTConstants::CS_); const auto &nodeValue = nodeP->value(); if (isNull(csNode) && !ci_equal(nodeValue, WKTConstants::VERT_CS) && !ci_equal(nodeValue, WKTConstants::BASEVERTCRS)) { - ThrowMissing(WKTConstants::CS); + ThrowMissing(WKTConstants::CS_); } auto cs = buildCS(csNode, node, UnitOfMeasure::NONE); auto verticalCS = nn_dynamic_pointer_cast<VerticalCS>(cs); @@ -3755,7 +3818,7 @@ CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) { Transformation::createGravityRelatedHeightToGeographic3D( PropertyMap().set(IdentifiedObject::NAME_KEY, transformationName), - crs, GeographicCRS::EPSG_4979, + crs, GeographicCRS::EPSG_4979, nullptr, stripQuotes(extensionChildren[1]), std::vector<PositionalAccuracyNNPtr>()); return nn_static_pointer_cast<CRS>(BoundCRS::create( @@ -3787,9 +3850,9 @@ WKTParser::Private::buildDerivedVerticalCRS(const WKTNodeNNPtr &node) { auto derivingConversion = buildConversion( derivingConversionNode, UnitOfMeasure::NONE, UnitOfMeasure::NONE); - auto &csNode = nodeP->lookForChild(WKTConstants::CS); + auto &csNode = nodeP->lookForChild(WKTConstants::CS_); if (isNull(csNode)) { - ThrowMissing(WKTConstants::CS); + ThrowMissing(WKTConstants::CS_); } auto cs = buildCS(csNode, node, UnitOfMeasure::NONE); @@ -3892,10 +3955,10 @@ BoundCRSNNPtr WKTParser::Private::buildBoundCRS(const WKTNodeNNPtr &node) { TemporalCSNNPtr WKTParser::Private::buildTemporalCS(const WKTNodeNNPtr &parentNode) { - auto &csNode = parentNode->GP()->lookForChild(WKTConstants::CS); + auto &csNode = parentNode->GP()->lookForChild(WKTConstants::CS_); if (isNull(csNode) && !ci_equal(parentNode->GP()->value(), WKTConstants::BASETIMECRS)) { - ThrowMissing(WKTConstants::CS); + ThrowMissing(WKTConstants::CS_); } auto cs = buildCS(csNode, parentNode, UnitOfMeasure::NONE); auto temporalCS = nn_dynamic_pointer_cast<TemporalCS>(cs); @@ -3953,9 +4016,9 @@ WKTParser::Private::buildEngineeringCRS(const WKTNodeNNPtr &node) { throw ParsingException("Missing EDATUM / ENGINEERINGDATUM node"); } - auto &csNode = nodeP->lookForChild(WKTConstants::CS); + auto &csNode = nodeP->lookForChild(WKTConstants::CS_); if (isNull(csNode) && !ci_equal(nodeP->value(), WKTConstants::BASEENGCRS)) { - ThrowMissing(WKTConstants::CS); + ThrowMissing(WKTConstants::CS_); } auto cs = buildCS(csNode, node, UnitOfMeasure::NONE); @@ -3998,9 +4061,9 @@ WKTParser::Private::buildDerivedEngineeringCRS(const WKTNodeNNPtr &node) { auto derivingConversion = buildConversion( derivingConversionNode, UnitOfMeasure::NONE, UnitOfMeasure::NONE); - auto &csNode = nodeP->lookForChild(WKTConstants::CS); + auto &csNode = nodeP->lookForChild(WKTConstants::CS_); if (isNull(csNode)) { - ThrowMissing(WKTConstants::CS); + ThrowMissing(WKTConstants::CS_); } auto cs = buildCS(csNode, node, UnitOfMeasure::NONE); @@ -4013,10 +4076,10 @@ WKTParser::Private::buildDerivedEngineeringCRS(const WKTNodeNNPtr &node) { ParametricCSNNPtr WKTParser::Private::buildParametricCS(const WKTNodeNNPtr &parentNode) { - auto &csNode = parentNode->GP()->lookForChild(WKTConstants::CS); + auto &csNode = parentNode->GP()->lookForChild(WKTConstants::CS_); if (isNull(csNode) && !ci_equal(parentNode->GP()->value(), WKTConstants::BASEPARAMCRS)) { - ThrowMissing(WKTConstants::CS); + ThrowMissing(WKTConstants::CS_); } auto cs = buildCS(csNode, parentNode, UnitOfMeasure::NONE); auto parametricCS = nn_dynamic_pointer_cast<ParametricCS>(cs); @@ -4086,9 +4149,9 @@ WKTParser::Private::buildDerivedProjectedCRS(const WKTNodeNNPtr &node) { auto conversion = buildConversion(conversionNode, linearUnit, angularUnit); - auto &csNode = nodeP->lookForChild(WKTConstants::CS); + auto &csNode = nodeP->lookForChild(WKTConstants::CS_); if (isNull(csNode) && !ci_equal(nodeP->value(), WKTConstants::PROJCS)) { - ThrowMissing(WKTConstants::CS); + ThrowMissing(WKTConstants::CS_); } auto cs = buildCS(csNode, node, UnitOfMeasure::NONE); return DerivedProjectedCRS::create(buildProperties(node), baseProjCRS, @@ -4255,16 +4318,31 @@ BaseObjectNNPtr WKTParser::Private::build(const WKTNodeNNPtr &node) { } if (ci_equal(name, WKTConstants::COORDINATEOPERATION)) { - return util::nn_static_pointer_cast<BaseObject>( - buildCoordinateOperation(node)); + auto transf = buildCoordinateOperation(node); + + const char *prefixes[] = { + "PROJ-based operation method: ", + "PROJ-based operation method (approximate): "}; + for (const char *prefix : prefixes) { + if (starts_with(transf->method()->nameStr(), prefix)) { + auto projString = + transf->method()->nameStr().substr(strlen(prefix)); + return util::nn_static_pointer_cast<BaseObject>( + PROJBasedOperation::create( + PropertyMap(), projString, transf->sourceCRS(), + transf->targetCRS(), + transf->coordinateOperationAccuracies())); + } + } + + return util::nn_static_pointer_cast<BaseObject>(transf); } if (ci_equal(name, WKTConstants::CONVERSION)) { auto conv = buildConversion(node, UnitOfMeasure::METRE, UnitOfMeasure::DEGREE); - if (conv->nameStr() == "PROJ-based coordinate operation" && - starts_with(conv->method()->nameStr(), + if (starts_with(conv->method()->nameStr(), "PROJ-based operation method: ")) { auto projString = conv->method()->nameStr().substr( strlen("PROJ-based operation method: ")); @@ -4345,15 +4423,97 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text, const auto authorities = dbContextNNPtr->getAuthorities(); for (const auto &authCandidate : authorities) { if (ci_equal(authCandidate, authName)) { - return AuthorityFactory::create(dbContextNNPtr, - authCandidate) - ->createCoordinateReferenceSystem(code); + factory = + AuthorityFactory::create(dbContextNNPtr, authCandidate); + try { + return factory->createCoordinateReferenceSystem(code); + } catch (...) { + // EPSG:4326+3855 + auto tokensCode = split(code, '+'); + if (tokensCode.size() == 2) { + auto crs1(factory->createCoordinateReferenceSystem( + tokensCode[0], false)); + auto crs2(factory->createCoordinateReferenceSystem( + tokensCode[1], false)); + return CompoundCRS::create( + util::PropertyMap().set( + IdentifiedObject::NAME_KEY, + crs1->nameStr() + " + " + crs2->nameStr()), + {crs1, crs2}); + } + throw; + } } } throw; } } + // OGC 07-092r2: para 7.5.2 + // URN combined references for compound coordinate reference systems + if (starts_with(text, "urn:ogc:def:crs,")) { + if (!dbContext) { + throw ParsingException("no database context specified"); + } + auto tokensComma = split(text, ','); + std::vector<CRSNNPtr> components; + std::string name; + for (size_t i = 1; i < tokensComma.size(); i++) { + tokens = split(tokensComma[i], ':'); + if (tokens.size() != 4) { + throw ParsingException( + concat("invalid crs component: ", tokensComma[i])); + } + const auto &type = tokens[0]; + auto factory = + AuthorityFactory::create(NN_NO_CHECK(dbContext), tokens[1]); + const auto &code = tokens[3]; + if (type == "crs") { + auto crs(factory->createCoordinateReferenceSystem(code, false)); + components.emplace_back(crs); + if (!name.empty()) { + name += " + "; + } + name += crs->nameStr(); + } else { + throw ParsingException( + concat("unexpected object type: ", type)); + } + } + return CompoundCRS::create( + util::PropertyMap().set(IdentifiedObject::NAME_KEY, name), + components); + } + + // OGC 07-092r2: para 7.5.3 + // 7.5.3 URN combined references for concatenated operations + if (starts_with(text, "urn:ogc:def:coordinateOperation,")) { + if (!dbContext) { + throw ParsingException("no database context specified"); + } + auto tokensComma = split(text, ','); + std::vector<CoordinateOperationNNPtr> components; + for (size_t i = 1; i < tokensComma.size(); i++) { + tokens = split(tokensComma[i], ':'); + if (tokens.size() != 4) { + throw ParsingException(concat( + "invalid coordinateOperation component: ", tokensComma[i])); + } + const auto &type = tokens[0]; + auto factory = + AuthorityFactory::create(NN_NO_CHECK(dbContext), tokens[1]); + const auto &code = tokens[3]; + if (type == "coordinateOperation") { + auto op(factory->createCoordinateOperation(code, false)); + components.emplace_back(op); + } else { + throw ParsingException( + concat("unexpected object type: ", type)); + } + } + return ConcatenatedOperation::createComputeMetadata(components, true); + } + // urn:ogc:def:crs:EPSG::4326 if (tokens.size() == 7) { if (!dbContext) { @@ -4454,9 +4614,18 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text, * <li>WKT string</li> * <li>PROJ string</li> * <li>database code, prefixed by its authoriy. e.g. "EPSG:4326"</li> - * <li>URN. e.g. "urn:ogc:def:crs:EPSG::4326", - * "urn:ogc:def:coordinateOperation:EPSG::1671"</li> - * <li>an objet name. e.g "WGS 84", "WGS 84 / UTM zone 31N". In that case as + * <li>OGC URN. e.g. "urn:ogc:def:crs:EPSG::4326", + * "urn:ogc:def:coordinateOperation:EPSG::1671", + * "urn:ogc:def:ellipsoid:EPSG::7001" + * or "urn:ogc:def:datum:EPSG::6326"</li> + * <li> OGC URN combining references for compound coordinate reference systems + * e.g. "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717" + * We also accept a custom abbreviated syntax EPSG:2393+5717 + * </li> + * <li> OGC URN combining references for concatenated operations + * e.g. + * "urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895,coordinateOperation:EPSG::1618"</li> + * <li>an Object name. e.g "WGS 84", "WGS 84 / UTM zone 31N". In that case as * uniqueness is not guaranteed, the function may apply heuristics to * determine the appropriate best match.</li> * </ul> @@ -4488,9 +4657,18 @@ BaseObjectNNPtr createFromUserInput(const std::string &text, * <li>WKT string</li> * <li>PROJ string</li> * <li>database code, prefixed by its authoriy. e.g. "EPSG:4326"</li> - * <li>URN. e.g. "urn:ogc:def:crs:EPSG::4326", - * "urn:ogc:def:coordinateOperation:EPSG::1671"</li> - * <li>an objet name. e.g "WGS 84", "WGS 84 / UTM zone 31N". In that case as + * <li>OGC URN. e.g. "urn:ogc:def:crs:EPSG::4326", + * "urn:ogc:def:coordinateOperation:EPSG::1671", + * "urn:ogc:def:ellipsoid:EPSG::7001" + * or "urn:ogc:def:datum:EPSG::6326"</li> + * <li> OGC URN combining references for compound coordinate reference systems + * e.g. "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717" + * We also accept a custom abbreviated syntax EPSG:2393+5717 + * </li> + * <li> OGC URN combining references for concatenated operations + * e.g. + * "urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895,coordinateOperation:EPSG::1618"</li> + * <li>an Object name. e.g "WGS 84", "WGS 84 / UTM zone 31N". In that case as * uniqueness is not guaranteed, the function may apply heuristics to * determine the appropriate best match.</li> * </ul> @@ -4744,7 +4922,7 @@ struct PROJStringFormatter::Private { }; std::vector<InversionStackElt> inversionStack_{InversionStackElt()}; bool omitProjLongLatIfPossible_ = false; - bool omitZUnitConversion_ = false; + std::vector<bool> omitZUnitConversion_{false}; DatabaseContextPtr dbContext_{}; bool useApproxTMerc_ = false; bool addNoDefs_ = true; @@ -5048,7 +5226,7 @@ const std::string &PROJStringFormatter::toString() const { first.paramValues[1].keyEquals("z_in") && first.paramValues[2].keyEquals("xy_out") && first.paramValues[3].keyEquals("z_out") && - second.paramValues[0].keyEquals("xy_in=") && + second.paramValues[0].keyEquals("xy_in") && second.paramValues[1].keyEquals("xy_out") && first.paramValues[0].value == second.paramValues[1].value && first.paramValues[2].value == second.paramValues[0].value) { @@ -5073,6 +5251,22 @@ const std::string &PROJStringFormatter::toString() const { break; } + // unitconvert (1), axisswap order=2,1, unitconvert(2) ==> + // axisswap order=2,1, unitconvert (1), unitconvert(2) which + // will get further optimized by previous case + if (i + 1 < d->steps_.size() && prevStep.name == "unitconvert" && + curStep.name == "axisswap" && curStepParamCount == 1 && + curStep.paramValues[0].equals("order", "2,1")) { + auto iterNext = iterCur; + ++iterNext; + auto &nextStep = *iterNext; + if (nextStep.name == "unitconvert") { + std::swap(*iterPrev, *iterCur); + changeDone = true; + break; + } + } + // axisswap order=2,1 followed by itself is a no-op if (curStep.name == "axisswap" && prevStep.name == "axisswap" && curStepParamCount == 1 && prevStepParamCount == 1 && @@ -5102,71 +5296,6 @@ const std::string &PROJStringFormatter::toString() const { } } - // axisswap order=2,1, pop/push v_3, axisswap order=2,1 -> can - // suppress axisswap - if (i + 1 < d->steps_.size() && prevStep.name == "axisswap" && - (curStep.name == "push" || curStep.name == "pop") && - prevStepParamCount == 1 && - prevStep.paramValues[0].equals("order", "2,1") && - curStepParamCount == 1 && curStep.paramValues[0].key == "v_3") { - auto iterNext = iterCur; - ++iterNext; - auto &nextStep = *iterNext; - if (nextStep.name == "axisswap" && - nextStep.paramValues.size() == 1 && - nextStep.paramValues[0].equals("order", "2,1")) { - d->steps_.erase(iterPrev); - d->steps_.erase(iterNext); - changeDone = true; - break; - } - } - - // push v_3, axisswap order=2,1, pop v_3 -> can suppress push/pop - if (i + 1 < d->steps_.size() && prevStep.name == "push" && - prevStepParamCount == 1 && - prevStep.paramValues[0].key == "v_3" && - curStep.name == "axisswap" && curStepParamCount == 1 && - curStep.paramValues[0].equals("order", "2,1")) { - auto iterNext = iterCur; - ++iterNext; - auto &nextStep = *iterNext; - if (nextStep.name == "pop" && - nextStep.paramValues.size() == 1 && - nextStep.paramValues[0].key == "v_3") { - d->steps_.erase(iterPrev); - d->steps_.erase(iterNext); - changeDone = true; - break; - } - } - - // unitconvert xy_in=A xy_out=B, pop/push v_3, unitconvert xy_in=B - // xy_out=A -> can suppress unitconvert - if (i + 1 < d->steps_.size() && prevStep.name == "unitconvert" && - (curStep.name == "push" || curStep.name == "pop") && - prevStepParamCount == 2 && - prevStep.paramValues[0].key == "xy_in" && - prevStep.paramValues[1].key == "xy_out" && - curStepParamCount == 1 && curStep.paramValues[0].key == "v_3") { - auto iterNext = iterCur; - ++iterNext; - auto &nextStep = *iterNext; - if (nextStep.name == "unitconvert" && - nextStep.paramValues.size() == 2 && - nextStep.paramValues[0].key == "xy_in" && - nextStep.paramValues[1].key == "xy_out" && - nextStep.paramValues[0].value == - prevStep.paramValues[1].value && - nextStep.paramValues[1].value == - prevStep.paramValues[0].value) { - d->steps_.erase(iterPrev); - d->steps_.erase(iterNext); - changeDone = true; - break; - } - } - // for practical purposes WGS84 and GRS80 ellipsoids are // equivalents (cartesian transform between both lead to differences // of the order of 1e-14 deg..). @@ -5335,6 +5464,11 @@ const std::string &PROJStringFormatter::toString() const { } } } + + if (d->result_.empty()) { + d->appendToResult("+proj=noop"); + } + return d->result_; } @@ -5382,7 +5516,7 @@ PROJStringSyntaxParser(const std::string &projString, std::vector<Step> &steps, { size_t i = 0; while (true) { - for (; isspace(c_str[i]); i++) { + for (; isspace(static_cast<unsigned char>(c_str[i])); i++) { } std::string token; bool in_string = false; @@ -5399,7 +5533,7 @@ PROJStringSyntaxParser(const std::string &projString, std::vector<Step> &steps, token += c_str[i]; i++; continue; - } else if (isspace(c_str[i])) { + } else if (isspace(static_cast<unsigned char>(c_str[i]))) { break; } token += c_str[i]; @@ -5805,15 +5939,21 @@ bool PROJStringFormatter::omitProjLongLatIfPossible() const { // --------------------------------------------------------------------------- -void PROJStringFormatter::setOmitZUnitConversion(bool omit) { - assert(d->omitZUnitConversion_ ^ omit); - d->omitZUnitConversion_ = omit; +void PROJStringFormatter::pushOmitZUnitConversion() { + d->omitZUnitConversion_.push_back(true); +} + +// --------------------------------------------------------------------------- + +void PROJStringFormatter::popOmitZUnitConversion() { + assert(d->omitZUnitConversion_.size() > 1); + d->omitZUnitConversion_.pop_back(); } // --------------------------------------------------------------------------- bool PROJStringFormatter::omitZUnitConversion() const { - return d->omitZUnitConversion_; + return d->omitZUnitConversion_.back(); } // --------------------------------------------------------------------------- @@ -6079,6 +6219,9 @@ static UnitOfMeasure _buildUnit(const LinearUnitDesc *unitsMatch) { static UnitOfMeasure _buildUnit(double to_meter_value) { // TODO: look-up in EPSG catalog + if (to_meter_value == 0) { + throw ParsingException("invalid unit value"); + } return UnitOfMeasure("unknown", to_meter_value, UnitOfMeasure::Type::LINEAR); } @@ -6593,9 +6736,9 @@ PROJStringParser::Private::processAxisSwap(Step &step, ? AxisDirection::NORTH : (axisType == AxisType::NORTH_POLE) ? AxisDirection::SOUTH - : (axisType == AxisType::SOUTH_POLE) - ? AxisDirection::NORTH - : AxisDirection::NORTH; + /*: (axisType == AxisType::SOUTH_POLE) + ? AxisDirection::NORTH*/ + : AxisDirection::NORTH; CoordinateSystemAxisNNPtr north = createAxis( northName, northAbbev, northDir, unit, (!isGeographic && axisType == AxisType::NORTH_POLE) @@ -6727,6 +6870,9 @@ static double getNumericValue(const std::string ¶mValue, } // --------------------------------------------------------------------------- +namespace { +template <class T> inline void ignoreRetVal(T) {} +} GeographicCRSNNPtr PROJStringParser::Private::buildGeographicCRS(int iStep, int iUnitConvert, @@ -6739,7 +6885,7 @@ PROJStringParser::Private::buildGeographicCRS(int iStep, int iUnitConvert, // units=m is often found in the wild. // No need to create a extension string for this - hasParamValue(step, "units"); + ignoreRetVal(hasParamValue(step, "units")); auto datum = buildDatum(step, title); @@ -6753,6 +6899,7 @@ PROJStringParser::Private::buildGeographicCRS(int iStep, int iUnitConvert, getNumericValue(getParamValue(step, "lon_0")) != 0.0)) { props.set("EXTENSION_PROJ4", projString_); } + props.set("IMPLICIT_CS", true); return GeographicCRS::create(props, datum, cs); } @@ -6771,7 +6918,7 @@ PROJStringParser::Private::buildGeocentricCRS(int iStep, int iUnitConvert) { auto datum = buildDatum(step, title); - UnitOfMeasure unit = UnitOfMeasure::METRE; + UnitOfMeasure unit = buildUnit(step, "units", ""); if (iUnitConvert >= 0) { auto &stepUnitConvert = steps_[iUnitConvert]; const std::string *xy_in = &getParamValue(stepUnitConvert, "xy_in"); @@ -6855,7 +7002,7 @@ PROJStringParser::Private::buildBoundOrCompoundCRSIfNeeded(int iStep, Transformation::createGravityRelatedHeightToGeographic3D( PropertyMap().set(IdentifiedObject::NAME_KEY, "unknown to WGS84 ellipsoidal height"), - crs, GeographicCRS::EPSG_4979, geoidgrids, + crs, GeographicCRS::EPSG_4979, nullptr, geoidgrids, std::vector<PositionalAccuracyNNPtr>()); auto boundvcrs = BoundCRS::create(vcrs, GeographicCRS::EPSG_4979, transformation); @@ -7243,6 +7390,8 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS( props.set("EXTENSION_PROJ4", projString_); } + props.set("IMPLICIT_CS", true); + CRSNNPtr crs = ProjectedCRS::create(props, geogCRS, NN_NO_CHECK(conv), cs); if (!hasParamValue(step, "geoidgrids") && diff --git a/src/iso19111/metadata.cpp b/src/iso19111/metadata.cpp index 6bf9d600..3725b072 100644 --- a/src/iso19111/metadata.cpp +++ b/src/iso19111/metadata.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * * Project: PROJ - * Purpose: ISO19111:2018 implementation + * Purpose: ISO19111:2019 implementation * Author: Even Rouault <even dot rouault at spatialys dot com> * ****************************************************************************** diff --git a/src/iso19111/static.cpp b/src/iso19111/static.cpp index 5de046f1..824047f0 100644 --- a/src/iso19111/static.cpp +++ b/src/iso19111/static.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * * Project: PROJ - * Purpose: ISO19111:2018 implementation + * Purpose: ISO19111:2019 implementation * Author: Even Rouault <even dot rouault at spatialys dot com> * ****************************************************************************** @@ -31,6 +31,7 @@ #endif #include "proj/common.hpp" +#include "proj/coordinateoperation.hpp" #include "proj/coordinatesystem.hpp" #include "proj/crs.hpp" #include "proj/datum.hpp" @@ -57,6 +58,7 @@ using namespace NS_PROJ::crs; using namespace NS_PROJ::datum; using namespace NS_PROJ::io; using namespace NS_PROJ::metadata; +using namespace NS_PROJ::operation; using namespace NS_PROJ::util; NS_PROJ_START @@ -215,7 +217,7 @@ DEFINE_WKT_CONSTANT(ANGLEUNIT); DEFINE_WKT_CONSTANT(SCALEUNIT); DEFINE_WKT_CONSTANT(TIMEUNIT); DEFINE_WKT_CONSTANT(ELLIPSOID); -DEFINE_WKT_CONSTANT(CS); +const std::string WKTConstants::CS_(createAndAddToConstantList("CS")); DEFINE_WKT_CONSTANT(ID); DEFINE_WKT_CONSTANT(PROJCRS); DEFINE_WKT_CONSTANT(BASEGEODCRS); @@ -271,6 +273,7 @@ DEFINE_WKT_CONSTANT(BASEVERTCRS); DEFINE_WKT_CONSTANT(BASEENGCRS); DEFINE_WKT_CONSTANT(BASEPARAMCRS); DEFINE_WKT_CONSTANT(BASETIMECRS); +DEFINE_WKT_CONSTANT(VERSION); DEFINE_WKT_CONSTANT(GEODETICCRS); DEFINE_WKT_CONSTANT(GEODETICDATUM); @@ -641,4 +644,13 @@ const GeographicCRSNNPtr // --------------------------------------------------------------------------- +/** \brief Key to set the operation version of a operation::CoordinateOperation + * + * The value is to be provided as a string. + */ +const std::string + operation::CoordinateOperation::OPERATION_VERSION_KEY("operationVersion"); + +// --------------------------------------------------------------------------- + NS_PROJ_END diff --git a/src/iso19111/util.cpp b/src/iso19111/util.cpp index d6cfa9f4..25207d5c 100644 --- a/src/iso19111/util.cpp +++ b/src/iso19111/util.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * * Project: PROJ - * Purpose: ISO19111:2018 implementation + * Purpose: ISO19111:2019 implementation * Author: Even Rouault <even dot rouault at spatialys dot com> * ****************************************************************************** diff --git a/src/jniproj.cpp b/src/jniproj.cpp index 59b5b2a0..6f441529 100644 --- a/src/jniproj.cpp +++ b/src/jniproj.cpp @@ -279,7 +279,7 @@ JNIEXPORT jcharArray JNICALL Java_org_proj4_PJ_getAxisDirections { PJ *pj = getPJ(env, object); if (pj) { - int length = strlen(pj->axis); + int length = static_cast<int>(strlen(pj->axis)); jcharArray array = env->NewCharArray(length); if (array) { jchar* axis = env->GetCharArrayElements(array, nullptr); diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake index f28a1d68..5a0a8070 100644 --- a/src/lib_proj.cmake +++ b/src/lib_proj.cmake @@ -6,245 +6,313 @@ message(STATUS "") # default config, shared on unix and static on Windows if(UNIX) - set(BUILD_LIBPROJ_SHARED_DEFAULT ON ) -endif(UNIX) -if( WIN32) - set(BUILD_LIBPROJ_SHARED_DEFAULT OFF) -endif(WIN32) -option(BUILD_LIBPROJ_SHARED "Build libproj library shared." ${BUILD_LIBPROJ_SHARED_DEFAULT}) + set(BUILD_LIBPROJ_SHARED_DEFAULT ON) +endif() +if(WIN32) + set(BUILD_LIBPROJ_SHARED_DEFAULT OFF) +endif() +option(BUILD_LIBPROJ_SHARED + "Build libproj library shared." ${BUILD_LIBPROJ_SHARED_DEFAULT}) if(BUILD_LIBPROJ_SHARED) set(PROJ_LIBRARY_TYPE SHARED) -else(BUILD_LIBPROJ_SHARED) +else() set(PROJ_LIBRARY_TYPE STATIC) -endif(BUILD_LIBPROJ_SHARED) +endif() option(USE_THREAD "Build libproj with thread/mutex support " ON) if(NOT USE_THREAD) - add_definitions( -DMUTEX_stub) -endif(NOT USE_THREAD) + add_definitions(-DMUTEX_stub) +endif() find_package(Threads QUIET) -if(USE_THREAD AND Threads_FOUND AND CMAKE_USE_WIN32_THREADS_INIT ) - add_definitions( -DMUTEX_win32) -elseif(USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT ) - add_definitions( -DMUTEX_pthread) +if(USE_THREAD AND Threads_FOUND AND CMAKE_USE_WIN32_THREADS_INIT) + add_definitions(-DMUTEX_win32) +elseif(USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) + add_definitions(-DMUTEX_pthread) elseif(USE_THREAD AND NOT Threads_FOUND) - message(FATAL_ERROR "No thread library found and thread/mutex support is required by USE_THREAD option") + message(FATAL_ERROR + "No thread library found and thread/mutex support is " + "required by USE_THREAD option") endif() -option(ENABLE_LTO "Build library with LTO optimization (if available)." OFF) +option(ENABLE_LTO + "Build library with LTO/IPO optimization (if available)." OFF) if(ENABLE_LTO) - if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") - include (CheckCXXSourceCompiles) - SET(CMAKE_REQUIRED_FLAGS "-Wl,-flto") - check_cxx_source_compiles("int main(){ return 0; }" COMPILER_SUPPORTS_FLTO_FLAG) - IF(COMPILER_SUPPORTS_FLTO_FLAG) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") - ENDIF() + # Determine ENABLE_LTO_METHOD to either "flag" or "property" + if(CMAKE_C_COMPILER_ID STREQUAL "Intel" + AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(ENABLE_LTO_METHOD "property") + elseif(CMAKE_VERSION VERSION_LESS 3.9) + # Maual checks required + if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + include(CheckCXXSourceCompiles) + set(CMAKE_REQUIRED_FLAGS "-Wl,-flto") + check_cxx_source_compiles("int main(){ return 0; }" + COMPILER_SUPPORTS_FLTO_FLAG) else() - include(CheckCXXCompilerFlag) - CHECK_CXX_COMPILER_FLAG("-flto" COMPILER_SUPPORTS_FLTO_FLAG) - if(COMPILER_SUPPORTS_FLTO_FLAG) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto") - endif() + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("-flto" COMPILER_SUPPORTS_FLTO_FLAG) endif() + set(ENABLE_LTO_METHOD "flag") + if(NOT COMPILER_SUPPORTS_FLTO_FLAG) + set(ENABLE_LTO OFF) + endif() + else() # CMake v3.9 + cmake_policy(SET CMP0069 NEW) + include(CheckIPOSupported) + check_ipo_supported(RESULT ENABLE_LTO) + set(ENABLE_LTO_METHOD "property") + endif() endif() +boost_report_value(ENABLE_LTO) ############################################## ### library source list and include_list ### ############################################## -SET(SRC_LIBPROJ_PROJECTIONS - projections/aeqd.cpp - projections/gnom.cpp - projections/laea.cpp - projections/mod_ster.cpp - projections/nsper.cpp - projections/nzmg.cpp - projections/ortho.cpp - projections/stere.cpp - projections/sterea.cpp - projections/aea.cpp - projections/bipc.cpp - projections/bonne.cpp - projections/eqdc.cpp - projections/isea.cpp - projections/ccon.cpp - projections/imw_p.cpp - projections/krovak.cpp - projections/lcc.cpp - projections/poly.cpp - projections/rpoly.cpp - projections/sconics.cpp - projections/rouss.cpp - projections/cass.cpp - projections/cc.cpp - projections/cea.cpp - projections/eqc.cpp - projections/gall.cpp - projections/labrd.cpp - projections/lsat.cpp - projections/misrsom.cpp - projections/merc.cpp - projections/mill.cpp - projections/ocea.cpp - projections/omerc.cpp - projections/somerc.cpp - projections/tcc.cpp - projections/tcea.cpp - projections/times.cpp - projections/tmerc.cpp - projections/tobmerc.cpp - projections/airy.cpp - projections/aitoff.cpp - projections/august.cpp - projections/bacon.cpp - projections/bertin1953.cpp - projections/chamb.cpp - projections/hammer.cpp - projections/lagrng.cpp - projections/larr.cpp - projections/lask.cpp - projections/latlong.cpp - projections/nicol.cpp - projections/ob_tran.cpp - projections/oea.cpp - projections/tpeqd.cpp - projections/vandg.cpp - projections/vandg2.cpp - projections/vandg4.cpp - projections/wag7.cpp - projections/lcca.cpp - projections/geos.cpp - projections/boggs.cpp - projections/collg.cpp - projections/comill.cpp - projections/crast.cpp - projections/denoy.cpp - projections/eck1.cpp - projections/eck2.cpp - projections/eck3.cpp - projections/eck4.cpp - projections/eck5.cpp - projections/fahey.cpp - projections/fouc_s.cpp - projections/gins8.cpp - projections/gstmerc.cpp - projections/gn_sinu.cpp - projections/goode.cpp - projections/igh.cpp - projections/hatano.cpp - projections/loxim.cpp - projections/mbt_fps.cpp - projections/mbtfpp.cpp - projections/mbtfpq.cpp - projections/moll.cpp - projections/nell.cpp - projections/nell_h.cpp - projections/patterson.cpp - projections/putp2.cpp - projections/putp3.cpp - projections/putp4p.cpp - projections/putp5.cpp - projections/putp6.cpp - projections/qsc.cpp - projections/robin.cpp - projections/sch.cpp - projections/sts.cpp - projections/urm5.cpp - projections/urmfps.cpp - projections/wag2.cpp - projections/wag3.cpp - projections/wink1.cpp - projections/wink2.cpp - projections/healpix.cpp - projections/natearth.cpp - projections/natearth2.cpp - projections/calcofi.cpp - projections/eqearth.cpp +set(SRC_LIBPROJ_PROJECTIONS + projections/aeqd.cpp + projections/gnom.cpp + projections/laea.cpp + projections/mod_ster.cpp + projections/nsper.cpp + projections/nzmg.cpp + projections/ortho.cpp + projections/stere.cpp + projections/sterea.cpp + projections/aea.cpp + projections/bipc.cpp + projections/bonne.cpp + projections/eqdc.cpp + projections/isea.cpp + projections/ccon.cpp + projections/imw_p.cpp + projections/krovak.cpp + projections/lcc.cpp + projections/poly.cpp + projections/rpoly.cpp + projections/sconics.cpp + projections/rouss.cpp + projections/cass.cpp + projections/cc.cpp + projections/cea.cpp + projections/eqc.cpp + projections/gall.cpp + projections/labrd.cpp + projections/lsat.cpp + projections/misrsom.cpp + projections/merc.cpp + projections/mill.cpp + projections/ocea.cpp + projections/omerc.cpp + projections/somerc.cpp + projections/tcc.cpp + projections/tcea.cpp + projections/times.cpp + projections/tmerc.cpp + projections/tobmerc.cpp + projections/airy.cpp + projections/aitoff.cpp + projections/august.cpp + projections/bacon.cpp + projections/bertin1953.cpp + projections/chamb.cpp + projections/hammer.cpp + projections/lagrng.cpp + projections/larr.cpp + projections/lask.cpp + projections/latlong.cpp + projections/nicol.cpp + projections/ob_tran.cpp + projections/oea.cpp + projections/tpeqd.cpp + projections/vandg.cpp + projections/vandg2.cpp + projections/vandg4.cpp + projections/wag7.cpp + projections/lcca.cpp + projections/geos.cpp + projections/boggs.cpp + projections/collg.cpp + projections/comill.cpp + projections/crast.cpp + projections/denoy.cpp + projections/eck1.cpp + projections/eck2.cpp + projections/eck3.cpp + projections/eck4.cpp + projections/eck5.cpp + projections/fahey.cpp + projections/fouc_s.cpp + projections/gins8.cpp + projections/gstmerc.cpp + projections/gn_sinu.cpp + projections/goode.cpp + projections/igh.cpp + projections/hatano.cpp + projections/loxim.cpp + projections/mbt_fps.cpp + projections/mbtfpp.cpp + projections/mbtfpq.cpp + projections/moll.cpp + projections/nell.cpp + projections/nell_h.cpp + projections/patterson.cpp + projections/putp2.cpp + projections/putp3.cpp + projections/putp4p.cpp + projections/putp5.cpp + projections/putp6.cpp + projections/qsc.cpp + projections/robin.cpp + projections/sch.cpp + projections/sts.cpp + projections/urm5.cpp + projections/urmfps.cpp + projections/wag2.cpp + projections/wag3.cpp + projections/wink1.cpp + projections/wink2.cpp + projections/healpix.cpp + projections/natearth.cpp + projections/natearth2.cpp + projections/calcofi.cpp + projections/eqearth.cpp ) -SET(SRC_LIBPROJ_CONVERSIONS - conversions/axisswap.cpp - conversions/cart.cpp - conversions/geoc.cpp - conversions/geocent.cpp - conversions/unitconvert.cpp +set(SRC_LIBPROJ_CONVERSIONS + conversions/axisswap.cpp + conversions/cart.cpp + conversions/geoc.cpp + conversions/geocent.cpp + conversions/noop.cpp + conversions/unitconvert.cpp ) -SET(SRC_LIBPROJ_TRANSFORMATIONS - transformations/affine.cpp - transformations/deformation.cpp - transformations/helmert.cpp - transformations/hgridshift.cpp - transformations/horner.cpp - transformations/molodensky.cpp - transformations/vgridshift.cpp +set(SRC_LIBPROJ_TRANSFORMATIONS + transformations/affine.cpp + transformations/deformation.cpp + transformations/helmert.cpp + transformations/hgridshift.cpp + transformations/horner.cpp + transformations/molodensky.cpp + transformations/vgridshift.cpp ) -SET(SRC_LIBPROJ_ISO19111 - iso19111/static.cpp - iso19111/util.cpp - iso19111/metadata.cpp - iso19111/common.cpp - iso19111/crs.cpp - iso19111/datum.cpp - iso19111/coordinatesystem.cpp - iso19111/coordinateoperation.cpp - iso19111/io.cpp - iso19111/internal.cpp - iso19111/factory.cpp - iso19111/c_api.cpp +set(SRC_LIBPROJ_ISO19111 + iso19111/static.cpp + iso19111/util.cpp + iso19111/metadata.cpp + iso19111/common.cpp + iso19111/crs.cpp + iso19111/datum.cpp + iso19111/coordinatesystem.cpp + iso19111/coordinateoperation.cpp + iso19111/io.cpp + iso19111/internal.cpp + iso19111/factory.cpp + iso19111/c_api.cpp ) -SET(SRC_LIBPROJ_CORE - pj_list.h proj_internal.h proj_math.h - aasincos.cpp adjlon.cpp - dmstor.cpp auth.cpp - deriv.cpp ell_set.cpp ellps.cpp errno.cpp - factors.cpp fwd.cpp init.cpp inv.cpp - list.cpp malloc.cpp mlfn.cpp msfn.cpp proj_mdist.cpp - open_lib.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 - gc_reader.cpp gridcatalog.cpp - nad_cvt.cpp nad_init.cpp nad_intr.cpp - apply_gridshift.cpp datums.cpp datum_set.cpp transform.cpp - geocent.cpp geocent.h utils.cpp gridinfo.cpp gridlist.cpp - jniproj.cpp mutex.cpp initcache.cpp apply_vgridshift.cpp geodesic.c - strtod.cpp math.cpp - 4D_api.cpp pipeline.cpp - internal.cpp - wkt_parser.hpp wkt_parser.cpp - wkt1_parser.h wkt1_parser.cpp - wkt1_generated_parser.h wkt1_generated_parser.c - wkt2_parser.h wkt2_parser.cpp - wkt2_generated_parser.h wkt2_generated_parser.c - ${CMAKE_CURRENT_BINARY_DIR}/proj_config.h +set(SRC_LIBPROJ_CORE + 4D_api.cpp + aasincos.cpp + adjlon.cpp + apply_gridshift.cpp + apply_vgridshift.cpp + auth.cpp + ctx.cpp + datum_set.cpp + datums.cpp + deriv.cpp + dmstor.cpp + ell_set.cpp + ellps.cpp + errno.cpp + factors.cpp + fileapi.cpp + fwd.cpp + gauss.cpp + gc_reader.cpp + geocent.cpp + geocent.h + geodesic.c + gridcatalog.cpp + gridinfo.cpp + gridlist.cpp + init.cpp + initcache.cpp + internal.cpp + inv.cpp + jniproj.cpp + list.cpp + log.cpp + malloc.cpp + math.cpp + mlfn.cpp + msfn.cpp + mutex.cpp + nad_cvt.cpp + nad_init.cpp + nad_intr.cpp + open_lib.cpp + param.cpp + phi2.cpp + pipeline.cpp + pj_list.h + pr_list.cpp + proj_internal.h + proj_math.h + proj_mdist.cpp + qsfn.cpp + release.cpp + 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 + wkt1_parser.h + wkt2_generated_parser.c + wkt2_generated_parser.h + wkt2_parser.cpp + wkt2_parser.h + wkt_parser.cpp + wkt_parser.hpp + zpoly1.cpp + ${CMAKE_CURRENT_BINARY_DIR}/proj_config.h ) set(HEADERS_LIBPROJ - proj_api.h - proj.h - proj_experimental.h - proj_constants.h - geodesic.h + proj_api.h + proj.h + proj_experimental.h + proj_constants.h + geodesic.h ) # Group source files for IDE source explorers (e.g. Visual Studio) -source_group("Header Files" FILES ${HEADERS_LIBPROJ}) -source_group("Source Files\\Core" FILES ${SRC_LIBPROJ_CORE}) -source_group("Source Files\\Conversions" FILES ${SRC_LIBPROJ_CONVERSIONS}) -source_group("Source Files\\Projections" FILES ${SRC_LIBPROJ_PROJECTIONS}) -source_group("Source Files\\Transformations" FILES ${SRC_LIBPROJ_TRANSFORMATIONS}) -source_group("Source Files\\ISO19111" FILES ${SRC_LIBPROJ_ISO19111}) +source_group("Header Files" + FILES ${HEADERS_LIBPROJ}) +source_group("Source Files\\Core" + FILES ${SRC_LIBPROJ_CORE}) +source_group("Source Files\\Conversions" + FILES ${SRC_LIBPROJ_CONVERSIONS}) +source_group("Source Files\\Projections" + FILES ${SRC_LIBPROJ_PROJECTIONS}) +source_group("Source Files\\Transformations" + FILES ${SRC_LIBPROJ_TRANSFORMATIONS}) +source_group("Source Files\\ISO19111" + FILES ${SRC_LIBPROJ_ISO19111}) include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories( ${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) source_group("CMake Files" FILES CMakeLists.txt) @@ -258,45 +326,77 @@ option(JNI_SUPPORT "Build support of java/jni wrapping for proj library" OFF) find_package(JNI QUIET) if(JNI_SUPPORT AND NOT JNI_FOUND) message(FATAL_ERROR "jni support is required but jni is not found") -endif(JNI_SUPPORT AND NOT JNI_FOUND) +endif() boost_report_value(JNI_SUPPORT) if(JNI_SUPPORT) - set(SRC_LIBPROJ_CORE ${SRC_LIBPROJ_CORE} - jniproj.cpp ) - set(HEADERS_LIBPROJ ${HEADERS_LIBPROJ} - org_proj4_PJ.h) + set(SRC_LIBPROJ_CORE + ${SRC_LIBPROJ_CORE} jniproj.cpp) + set(HEADERS_LIBPROJ + ${HEADERS_LIBPROJ} org_proj4_PJ.h) source_group("Source Files\\JNI" FILES ${SRC_LIBPROJ_JNI}) add_definitions(-DJNI_ENABLED) - include_directories( ${JNI_INCLUDE_DIRS}) + include_directories(${JNI_INCLUDE_DIRS}) boost_report_value(JNI_INCLUDE_DIRS) -endif(JNI_SUPPORT) +endif() ################################################# ## targets: libproj and proj_config.h ################################################# -set(ALL_LIBPROJ_SOURCES ${SRC_LIBPROJ_CORE} - ${SRC_LIBPROJ_CONVERSIONS} - ${SRC_LIBPROJ_PROJECTIONS} - ${SRC_LIBPROJ_TRANSFORMATIONS} - ${SRC_LIBPROJ_ISO19111} +set(ALL_LIBPROJ_SOURCES + ${SRC_LIBPROJ_CORE} + ${SRC_LIBPROJ_CONVERSIONS} + ${SRC_LIBPROJ_PROJECTIONS} + ${SRC_LIBPROJ_TRANSFORMATIONS} + ${SRC_LIBPROJ_ISO19111} ) -set(ALL_LIBPROJ_HEADERS ${HEADERS_LIBPROJ} ) +set(ALL_LIBPROJ_HEADERS ${HEADERS_LIBPROJ}) # Core targets configuration string(TOLOWER "${PROJECT_INTERN_NAME}" PROJECTNAMEL) set(PROJ_CORE_TARGET ${PROJECTNAMEL}) proj_target_output_name(${PROJ_CORE_TARGET} PROJ_CORE_TARGET_OUTPUT_NAME) -add_library( ${PROJ_CORE_TARGET} - ${PROJ_LIBRARY_TYPE} - ${ALL_LIBPROJ_SOURCES} - ${ALL_LIBPROJ_HEADERS} - ${PROJ_RESOURCES} ) +add_library( + ${PROJ_CORE_TARGET} + ${PROJ_LIBRARY_TYPE} + ${ALL_LIBPROJ_SOURCES} + ${ALL_LIBPROJ_HEADERS} + ${PROJ_RESOURCES} +) +target_compile_options(${PROJ_CORE_TARGET} + PRIVATE $<$<COMPILE_LANGUAGE:C>:${PROJ_C_WARN_FLAGS}> + PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${PROJ_CXX_WARN_FLAGS}> +) + +# Tell Intel compiler to do arithmetic accurately. This is needed to stop the +# compiler from ignoring parentheses in expressions like (a + b) + c and from +# simplifying 0.0 + x to x (which is wrong if x = -0.0). +if("${CMAKE_C_COMPILER_ID}" STREQUAL "Intel") + if(MSVC) + set(FP_PRECISE "/fp:precise") + else() + set(FP_PRECISE "-fp-model precise") + endif() + # Apply to source files that require this option + set_source_files_properties( + geodesic.c + PROPERTIES COMPILE_FLAGS ${FP_PRECISE}) +endif() + +if(ENABLE_LTO) + if(ENABLE_LTO_METHOD STREQUAL "property") + set_property(TARGET ${PROJ_CORE_TARGET} + PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) + elseif(ENABLE_LTO_METHOD STREQUAL "flag") + # pre-CMake 3.9 workaround + target_compile_options(${PROJ_CORE_TARGET} PRIVATE -flto) + endif() +endif() -if (NOT CMAKE_VERSION VERSION_LESS 2.8.11) - target_include_directories (${PROJ_CORE_TARGET} INTERFACE +if(NOT CMAKE_VERSION VERSION_LESS 2.8.11) + target_include_directories(${PROJ_CORE_TARGET} INTERFACE $<INSTALL_INTERFACE:${INCLUDEDIR}>) -endif () +endif() if(WIN32) set_target_properties(${PROJ_CORE_TARGET} @@ -319,45 +419,47 @@ else() endif() set_target_properties(${PROJ_CORE_TARGET} - PROPERTIES - LINKER_LANGUAGE CXX) + PROPERTIES + LINKER_LANGUAGE CXX) ############################################## # Link properties ############################################## set(PROJ_LIBRARIES ${PROJ_CORE_TARGET}) -set(PROJ_LIBRARIES ${PROJ_LIBRARIES} PARENT_SCOPE) # hack, required for test/unit +# hack, required for test/unit +set(PROJ_LIBRARIES ${PROJ_LIBRARIES} PARENT_SCOPE) if(UNIX) - find_library(M_LIB m) - if(M_LIB) - TARGET_LINK_LIBRARIES(${PROJ_CORE_TARGET} -lm) - endif() -endif(UNIX) + find_library(M_LIB m) + if(M_LIB) + target_link_libraries(${PROJ_CORE_TARGET} -lm) + endif() +endif() if(USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) - TARGET_LINK_LIBRARIES(${PROJ_CORE_TARGET} ${CMAKE_THREAD_LIBS_INIT}) -endif(USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) + target_link_libraries(${PROJ_CORE_TARGET} ${CMAKE_THREAD_LIBS_INIT}) +endif() include_directories(${SQLITE3_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(${PROJ_CORE_TARGET} ${SQLITE3_LIBRARY}) +target_link_libraries(${PROJ_CORE_TARGET} ${SQLITE3_LIBRARY}) if(MSVC) - target_compile_definitions(${PROJ_CORE_TARGET} PRIVATE PROJ_MSVC_DLL_EXPORT=1) + target_compile_definitions(${PROJ_CORE_TARGET} + PRIVATE PROJ_MSVC_DLL_EXPORT=1) endif() ############################################## # install ############################################## install(TARGETS ${PROJ_CORE_TARGET} - EXPORT targets - RUNTIME DESTINATION ${BINDIR} - LIBRARY DESTINATION ${LIBDIR} - ARCHIVE DESTINATION ${LIBDIR} - FRAMEWORK DESTINATION ${FRAMEWORKDIR}) + EXPORT targets + RUNTIME DESTINATION ${BINDIR} + LIBRARY DESTINATION ${LIBDIR} + ARCHIVE DESTINATION ${LIBDIR} + FRAMEWORK DESTINATION ${FRAMEWORKDIR}) if(NOT BUILD_FRAMEWORKS_AND_BUNDLE) install(FILES ${ALL_LIBPROJ_HEADERS} - DESTINATION ${INCLUDEDIR}) -endif(NOT BUILD_FRAMEWORKS_AND_BUNDLE) + DESTINATION ${INCLUDEDIR}) +endif() ############################################## # Core configuration summary diff --git a/src/mutex.cpp b/src/mutex.cpp index 12251f0f..da415e55 100644 --- a/src/mutex.cpp +++ b/src/mutex.cpp @@ -25,14 +25,6 @@ * DEALINGS IN THE SOFTWARE. *****************************************************************************/ - -/* projects.h and windows.h conflict - avoid this! */ - -#if defined(MUTEX_pthread) && !defined(_XOPEN_SOURCE) && !defined(__sun) -/* For pthread_mutexattr_settype */ -#define _XOPEN_SOURCE 500 -#endif - /* For PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */ #ifndef _GNU_SOURCE #define _GNU_SOURCE diff --git a/src/nad_init.cpp b/src/nad_init.cpp index d9701e70..315318be 100644 --- a/src/nad_init.cpp +++ b/src/nad_init.cpp @@ -265,7 +265,6 @@ struct CTABLE *nad_ctable2_init( projCtx ctx, struct projFileAPI_t* fileapi ) struct CTABLE *nad_init(projCtx ctx, char *name) { - char fname[MAX_PATH_FILENAME+1]; struct CTABLE *ct; PAFile fid; @@ -274,8 +273,7 @@ struct CTABLE *nad_init(projCtx ctx, char *name) /* -------------------------------------------------------------------- */ /* Open the file using the usual search rules. */ /* -------------------------------------------------------------------- */ - strcpy(fname, name); - if (!(fid = pj_open_lib(ctx, fname, "rb"))) { + if (!(fid = pj_open_lib(ctx, name, "rb"))) { return nullptr; } diff --git a/src/nad_intr.cpp b/src/nad_intr.cpp index 2c301ef8..8dc2f652 100644 --- a/src/nad_intr.cpp +++ b/src/nad_intr.cpp @@ -1,9 +1,8 @@ /* Determine nad table correction value */ #define PJ_LIB__ -#include "proj_internal.h" -#include "proj_math.h" #include "proj.h" #include "proj_internal.h" +#include "proj_math.h" PJ_LP nad_intr(PJ_LP t, struct CTABLE *ct) { PJ_LP val, frct; diff --git a/src/open_lib.cpp b/src/open_lib.cpp index 510704e9..01f626e8 100644 --- a/src/open_lib.cpp +++ b/src/open_lib.cpp @@ -34,6 +34,7 @@ #define FROM_PROJ_CPP #endif +#include <assert.h> #include <errno.h> #include <stddef.h> #include <stdio.h> @@ -194,15 +195,30 @@ pj_open_lib_ex(projCtx ctx, const char *name, const char *mode, sysname = name; /* or try to use application provided file finder */ - else if( ctx && ctx->file_finder != nullptr && (sysname = ctx->file_finder( ctx, name, ctx->file_finder_user_data )) != nullptr ) + else if( ctx->file_finder != nullptr && (sysname = ctx->file_finder( ctx, name, ctx->file_finder_user_data )) != nullptr ) ; - else if( ctx && ctx->file_finder_legacy != nullptr && (sysname = ctx->file_finder_legacy( name )) != nullptr ) + else if( ctx->file_finder_legacy != nullptr && (sysname = ctx->file_finder_legacy( name )) != nullptr ) ; - /* or is environment PROJ_LIB defined */ + /* The user has search paths set */ + else if( !ctx->search_paths.empty() ) { + for( const auto& path: ctx->search_paths ) { + try { + fname = path; + fname += DIR_CHAR; + fname += name; + sysname = fname.c_str(); + fid = pj_ctx_fopen(ctx, sysname, mode); + } catch( const std::exception& ) + { + } + if( fid ) + break; + } + } + /* if is environment PROJ_LIB defined */ else if ((sysname = getenv("PROJ_LIB")) != nullptr) { - auto paths = NS_PROJ::internal::split(std::string(sysname), dirSeparator); for( const auto& path: paths ) { fname = path; @@ -213,16 +229,18 @@ pj_open_lib_ex(projCtx ctx, const char *name, const char *mode, if( fid ) break; } - /* or hardcoded path */ } else if ((sysname = proj_lib_name) != nullptr) { fname = sysname; fname += DIR_CHAR; fname += name; sysname = fname.c_str(); - } else /* just try it bare bones */ + /* just try it bare bones */ + } else { sysname = name; + } + assert(sysname); // to make Coverity Scan happy if ( fid != nullptr || (fid = pj_ctx_fopen(ctx, sysname, mode)) != nullptr) { if( out_full_filename != nullptr && out_full_filename_size > 0 ) @@ -233,33 +251,6 @@ pj_open_lib_ex(projCtx ctx, const char *name, const char *mode, errno = 0; } - /* If none of those work and we have a search path, try it */ - if (!fid && ctx && !ctx->search_paths.empty() ) - { - for( const auto& path: ctx->search_paths ) { - try { - fname = path; - fname += DIR_CHAR; - fname += name; - sysname = fname.c_str(); - fid = pj_ctx_fopen(ctx, sysname, mode); - } catch( const std::exception& ) - { - } - if( fid ) - break; - } - if (fid) - { - if( out_full_filename != nullptr && out_full_filename_size > 0 ) - { - strncpy(out_full_filename, sysname, out_full_filename_size); - out_full_filename[out_full_filename_size-1] = '\0'; - } - errno = 0; - } - } - if( ctx->last_errno == 0 && errno != 0 ) pj_ctx_set_errno( ctx, errno ); diff --git a/src/pipeline.cpp b/src/pipeline.cpp index 39563c65..afa3b19a 100644 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -105,7 +105,6 @@ Thomas Knudsen, thokn@sdfe.dk, 2016-05-20 #include "geodesic.h" #include "proj.h" #include "proj_internal.h" -#include "proj_internal.h" PROJ_HEAD(pipeline, "Transformation pipeline manager"); PROJ_HEAD(pop, "Retrieve coordinate value from pipeline stack"); diff --git a/src/pj_list.h b/src/pj_list.h index 8ab4cdc0..0923bba8 100644 --- a/src/pj_list.h +++ b/src/pj_list.h @@ -106,6 +106,7 @@ PROJ_HEAD(nell_h, "Nell-Hammer") PROJ_HEAD(nicol, "Nicolosi Globular") PROJ_HEAD(nsper, "Near-sided perspective") PROJ_HEAD(nzmg, "New Zealand Map Grid") +PROJ_HEAD(noop, "No operation") PROJ_HEAD(ob_tran, "General Oblique Transformation") PROJ_HEAD(ocea, "Oblique Cylindrical Equal Area") PROJ_HEAD(oea, "Oblated Equal Area") @@ -153,7 +153,7 @@ extern "C" { /* The version numbers should be updated with every release! **/ #define PROJ_VERSION_MAJOR 6 -#define PROJ_VERSION_MINOR 0 +#define PROJ_VERSION_MINOR 1 #define PROJ_VERSION_PATCH 0 extern char const PROJ_DLL pj_release[]; /* global release id string */ @@ -356,6 +356,7 @@ int PROJ_DLL proj_context_get_use_proj4_init_rules(PJ_CONTEXT *ctx, int from_leg PJ PROJ_DLL *proj_create (PJ_CONTEXT *ctx, const char *definition); PJ PROJ_DLL *proj_create_argv (PJ_CONTEXT *ctx, int argc, char **argv); PJ PROJ_DLL *proj_create_crs_to_crs(PJ_CONTEXT *ctx, const char *source_crs, const char *target_crs, PJ_AREA *area); +PJ PROJ_DLL *proj_normalize_for_visualization(PJ_CONTEXT *ctx, const PJ* obj); PJ PROJ_DLL *proj_destroy (PJ *P); @@ -999,7 +1000,10 @@ int PROJ_DLL proj_coordoperation_get_method_info(PJ_CONTEXT *ctx, const char **out_method_auth_name, const char **out_method_code); -int PROJ_DLL proj_coordoperation_is_instanciable(PJ_CONTEXT *ctx, +int PROJ_DLL proj_coordoperation_is_instantiable(PJ_CONTEXT *ctx, + const PJ *coordoperation); + +int PROJ_DLL proj_coordoperation_has_ballpark_transformation(PJ_CONTEXT *ctx, const PJ *coordoperation); int PROJ_DLL proj_coordoperation_get_param_count(PJ_CONTEXT *ctx, diff --git a/src/proj_api.h b/src/proj_api.h index 5c4d5e7a..53b0edfa 100644 --- a/src/proj_api.h +++ b/src/proj_api.h @@ -38,7 +38,7 @@ #endif #ifndef PJ_VERSION -#define PJ_VERSION 600 +#define PJ_VERSION 610 #endif #ifdef PROJ_RENAME_SYMBOLS diff --git a/src/proj_internal.h b/src/proj_internal.h index 14b69492..8c365793 100644 --- a/src/proj_internal.h +++ b/src/proj_internal.h @@ -203,7 +203,7 @@ PJ_COORD PROJ_DLL pj_approx_3D_trans (PJ *P, PJ_DIRECTION direction, PJ_COORD co /* Grid functionality */ int proj_vgrid_init(PJ *P, const char *grids); int proj_hgrid_init(PJ *P, const char *grids); -double proj_vgrid_value(PJ *P, PJ_LP lp); +double proj_vgrid_value(PJ *P, PJ_LP lp, double vmultiplier); PJ_LP proj_hgrid_value(PJ *P, PJ_LP lp); PJ_LP proj_hgrid_apply(PJ *P, PJ_LP lp, PJ_DIRECTION direction); @@ -624,7 +624,7 @@ struct FACTORS { #define PJD_ERR_NO_COLON_IN_INIT_STRING -3 #define PJD_ERR_PROJ_NOT_NAMED -4 #define PJD_ERR_UNKNOWN_PROJECTION_ID -5 -#define PJD_ERR_ECCENTRICITY_IS_ONE -6 +#define PJD_ERR_INVALID_ECCENTRICITY -6 #define PJD_ERR_UNKNOWN_UNIT_ID -7 #define PJD_ERR_INVALID_BOOLEAN_PARAM -8 #define PJD_ERR_UNKNOWN_ELLP_PARAM -9 @@ -648,7 +648,7 @@ struct FACTORS { #define PJD_ERR_W_OR_M_ZERO_OR_LESS -27 #define PJD_ERR_LSAT_NOT_IN_RANGE -28 #define PJD_ERR_PATH_NOT_IN_RANGE -29 -#define PJD_ERR_H_LESS_THAN_ZERO -30 +#define PJD_ERR_INVALID_H -30 #define PJD_ERR_K_LESS_THAN_ZERO -31 #define PJD_ERR_LAT_1_OR_2_ZERO_OR_90 -32 #define PJD_ERR_LAT_0_OR_ALPHA_EQ_90 -33 @@ -679,6 +679,7 @@ struct FACTORS { #define PJD_ERR_INVALID_ARG -58 #define PJD_ERR_INCONSISTENT_UNIT -59 #define PJD_ERR_MUTUALLY_EXCLUSIVE_ARGS -60 +#define PJD_ERR_GENERIC_ERROR -61 /* NOTE: Remember to update src/strerrno.cpp, src/apps/gie.cpp and transient_error in */ /* src/transform.cpp when adding new value */ @@ -898,12 +899,6 @@ int pj_gc_apply_gridshift( PJ *defn, int inverse, long point_count, int point_offset, double *x, double *y, double *z ); -PJ_GRIDINFO *pj_gc_findgrid( projCtx_t *ctx, - PJ_GridCatalog *catalog, int after, - PJ_LP location, double date, - PJ_Region *optional_region, - double *grid_date ); - double pj_gc_parsedate( projCtx_t *, const char * ); void *proj_mdist_ini(double); diff --git a/src/proj_symbol_rename.h b/src/proj_symbol_rename.h index 0ce342fd..b6e887ca 100644 --- a/src/proj_symbol_rename.h +++ b/src/proj_symbol_rename.h @@ -115,7 +115,7 @@ #define proj_coordoperation_get_param_count internal_proj_coordoperation_get_param_count #define proj_coordoperation_get_param_index internal_proj_coordoperation_get_param_index #define proj_coordoperation_get_towgs84_values internal_proj_coordoperation_get_towgs84_values -#define proj_coordoperation_is_instanciable internal_proj_coordoperation_is_instanciable +#define proj_coordoperation_is_instantiable internal_proj_coordoperation_is_instantiable #define proj_create internal_proj_create #define proj_create_argv internal_proj_create_argv #define proj_create_cartesian_2D_cs internal_proj_create_cartesian_2D_cs diff --git a/src/projections/aea.cpp b/src/projections/aea.cpp index 9a0c4656..721ea3c9 100644 --- a/src/projections/aea.cpp +++ b/src/projections/aea.cpp @@ -99,7 +99,7 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoid/spheroid, forward */ +static PJ_XY aea_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoid/spheroid, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); Q->rho = Q->c - (Q->ellips ? Q->n * pj_qsfn(sin(lp.phi), P->e, P->one_es) : Q->n2 * sin(lp.phi));; @@ -114,7 +114,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoid/spheroid, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoid/spheroid, inverse */ +static PJ_LP aea_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoid/spheroid, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); if( (Q->rho = hypot(xy.x, xy.y = Q->rho0 - xy.y)) != 0.0 ) { @@ -152,9 +152,11 @@ static PJ *setup(PJ *P) { int secant; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = aea_e_inverse; + P->fwd = aea_e_forward; + if (fabs(Q->phi1) > M_HALFPI || fabs(Q->phi2) > M_HALFPI) + return destructor(P, PJD_ERR_LAT_LARGER_THAN_90); if (fabs(Q->phi1 + Q->phi2) < EPS10) return destructor(P, PJD_ERR_CONIC_LAT_EQUAL); Q->n = sinphi = sin(Q->phi1); @@ -178,6 +180,10 @@ static PJ *setup(PJ *P) { return destructor(P, 0); Q->n = (m1 * m1 - m2 * m2) / (ml2 - ml1); + if (Q->n == 0) { + // Not quite, but es is very close to 1... + return destructor(P, PJD_ERR_INVALID_ECCENTRICITY); + } } Q->ec = 1. - .5 * P->one_es * log((1. - P->e) / (1. + P->e)) / P->e; diff --git a/src/projections/aeqd.cpp b/src/projections/aeqd.cpp index 8566062d..04c3662e 100644 --- a/src/projections/aeqd.cpp +++ b/src/projections/aeqd.cpp @@ -91,7 +91,7 @@ static PJ_XY e_guam_fwd(PJ_LP lp, PJ *P) { /* Guam elliptical */ } -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY aeqd_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double coslam, cosphi, sinphi, rho; @@ -130,7 +130,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY aeqd_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double coslam, cosphi, sinphi; @@ -195,7 +195,7 @@ static PJ_LP e_guam_inv(PJ_XY xy, PJ *P) { /* Guam elliptical */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP aeqd_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double c; @@ -227,7 +227,7 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP aeqd_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cosc, c_rh, sinc; @@ -291,8 +291,8 @@ PJ *PROJECTION(aeqd) { Q->cosph0 = cos(P->phi0); } if (P->es == 0.0) { - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = aeqd_s_inverse; + P->fwd = aeqd_s_forward; } else { if (!(Q->en = pj_enfn(P->es))) return pj_default_destructor (P, 0); @@ -310,14 +310,13 @@ PJ *PROJECTION(aeqd) { break; case EQUIT: case OBLIQ: - P->inv = e_inverse; P->fwd = e_forward; Q->N1 = 1. / sqrt(1. - P->es * Q->sinph0 * Q->sinph0); Q->G = Q->sinph0 * (Q->He = P->e / sqrt(P->one_es)); Q->He *= Q->cosph0; break; } - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = aeqd_e_inverse; + P->fwd = aeqd_e_forward; } } diff --git a/src/projections/airy.cpp b/src/projections/airy.cpp index f7068061..91b4b7a2 100644 --- a/src/projections/airy.cpp +++ b/src/projections/airy.cpp @@ -58,7 +58,7 @@ struct pj_opaque { # define EPS 1.e-10 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY airy_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double sinlam, coslam, cosphi, sinphi, t, s, Krho, cosz; @@ -79,6 +79,10 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } if (fabs(s = 1. - cosz) > EPS) { t = 0.5 * (1. + cosz); + if(t == 0) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } Krho = -log(t)/s - Q->Cb / t; } else Krho = 0.5 - Q->Cb; @@ -147,7 +151,7 @@ PJ *PROJECTION(airy) { Q->cosph0 = cos(P->phi0); } } - P->fwd = s_forward; + P->fwd = airy_s_forward; P->es = 0.; return P; } diff --git a/src/projections/aitoff.cpp b/src/projections/aitoff.cpp index 127841ff..dadae12d 100644 --- a/src/projections/aitoff.cpp +++ b/src/projections/aitoff.cpp @@ -58,11 +58,11 @@ PROJ_HEAD(wintri, "Winkel Tripel") "\n\tMisc Sph\n\tlat_1"; #if 0 -FORWARD(s_forward); /* spheroid */ +FORWARD(aitoff_s_forward); /* spheroid */ #endif -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY aitoff_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double c, d; @@ -100,7 +100,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ * ************************************************************************************/ -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP aitoff_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); int iter, MAXITER = 10, round = 0, MAXROUND = 20; @@ -116,15 +116,20 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ sl = sin(lp.lam * 0.5); cl = cos(lp.lam * 0.5); sp = sin(lp.phi); cp = cos(lp.phi); D = cp * cl; - C = 1. - D * D; - D = acos(D) / pow(C, 1.5); - f1 = 2. * D * C * cp * sl; - f2 = D * C * sp; - f1p = 2.* (sl * cl * sp * cp / C - D * sp * sl); - f1l = cp * cp * sl * sl / C + D * cp * cl * sp * sp; - f2p = sp * sp * cl / C + D * sl * sl * cp; - f2l = 0.5 * (sp * cp * sl / C - D * sp * cp * cp * sl * cl); - if (Q->mode == WINKEL_TRIPEL) { + C = 1. - D * D; + const double denom = pow(C, 1.5); + if( denom == 0 ) { + proj_errno_set(P, PJD_ERR_NON_CONVERGENT); + return lp; + } + D = acos(D) / denom; + f1 = 2. * D * C * cp * sl; + f2 = D * C * sp; + f1p = 2.* (sl * cl * sp * cp / C - D * sp * sl); + f1l = cp * cp * sl * sl / C + D * cp * cl * sp * sp; + f2p = sp * sp * cl / C + D * sl * sl * cp; + f2l = 0.5 * (sp * cp * sl / C - D * sp * cp * cp * sl * cl); + if (Q->mode == WINKEL_TRIPEL) { f1 = 0.5 * (f1 + lp.lam * Q->cosphi1); f2 = 0.5 * (f2 + lp.phi); f1p *= 0.5; @@ -156,18 +161,18 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ } while (((fabs(xy.x-x) > EPSILON) || (fabs(xy.y-y) > EPSILON)) && (round++ < MAXROUND)); if (iter == MAXITER && round == MAXROUND) - { - pj_ctx_set_errno( 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); */ - } + { + pj_ctx_set_errno( 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); */ + } return lp; } static PJ *setup(PJ *P) { - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = aitoff_s_inverse; + P->fwd = aitoff_s_forward; P->es = 0.; return P; } diff --git a/src/projections/august.cpp b/src/projections/august.cpp index 3523034e..2104c3cc 100644 --- a/src/projections/august.cpp +++ b/src/projections/august.cpp @@ -9,7 +9,7 @@ PROJ_HEAD(august, "August Epicycloidal") "\n\tMisc Sph, no inv"; #define M 1.333333333333333 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY august_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double t, c1, c, x1, x12, y1, y12; (void) P; @@ -29,7 +29,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ *PROJECTION(august) { P->inv = nullptr; - P->fwd = s_forward; + P->fwd = august_s_forward; P->es = 0.; return P; } diff --git a/src/projections/bacon.cpp b/src/projections/bacon.cpp index c713a989..5db2d854 100644 --- a/src/projections/bacon.cpp +++ b/src/projections/bacon.cpp @@ -20,7 +20,7 @@ PROJ_HEAD(ortel, "Ortelius Oval") "\n\tMisc Sph, no inv"; PROJ_HEAD(bacon, "Bacon Globular") "\n\tMisc Sph, no inv"; -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY bacon_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double ax, f; @@ -50,7 +50,7 @@ PJ *PROJECTION(bacon) { Q->bacn = 1; Q->ortl = 0; P->es = 0.; - P->fwd = s_forward; + P->fwd = bacon_s_forward; return P; } @@ -63,7 +63,7 @@ PJ *PROJECTION(apian) { Q->bacn = Q->ortl = 0; P->es = 0.; - P->fwd = s_forward; + P->fwd = bacon_s_forward; return P; } @@ -77,6 +77,6 @@ PJ *PROJECTION(ortel) { Q->bacn = 0; Q->ortl = 1; P->es = 0.; - P->fwd = s_forward; + P->fwd = bacon_s_forward; return P; } diff --git a/src/projections/bertin1953.cpp b/src/projections/bertin1953.cpp index 96de6d4b..63154084 100644 --- a/src/projections/bertin1953.cpp +++ b/src/projections/bertin1953.cpp @@ -14,7 +14,6 @@ #include <errno.h> #include <math.h> -#include "proj_internal.h" #include "proj.h" #include "proj_internal.h" @@ -28,7 +27,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { +static PJ_XY bertin1953_s_forward (PJ_LP lp, PJ *P) { PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -90,7 +89,7 @@ PJ *PROJECTION(bertin1953) { Q->sin_delta_gamma = 0.; P->es = 0.; - P->fwd = s_forward; + P->fwd = bertin1953_s_forward; return P; } diff --git a/src/projections/bipc.cpp b/src/projections/bipc.cpp index 5cfef11f..9fd2fc6f 100644 --- a/src/projections/bipc.cpp +++ b/src/projections/bipc.cpp @@ -36,7 +36,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY bipc_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cphi, sphi, tphi, t, al, Az, z, Av, cdlam, sdlam, r; @@ -113,7 +113,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP bipc_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double t, r, rp, rl, al, z = 0.0, fAz, Az, s, c, Av; @@ -169,8 +169,8 @@ PJ *PROJECTION(bipc) { P->opaque = Q; Q->noskew = pj_param(P->ctx, P->params, "bns").i; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = bipc_s_inverse; + P->fwd = bipc_s_forward; P->es = 0.; return P; } diff --git a/src/projections/boggs.cpp b/src/projections/boggs.cpp index 5502d493..e7278904 100644 --- a/src/projections/boggs.cpp +++ b/src/projections/boggs.cpp @@ -12,7 +12,7 @@ PROJ_HEAD(boggs, "Boggs Eumorphic") "\n\tPCyl, no inv, Sph"; # define FYC 0.49931 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY boggs_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double theta, th1, c; int i; @@ -39,6 +39,6 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ *PROJECTION(boggs) { P->es = 0.; - P->fwd = s_forward; + P->fwd = boggs_s_forward; return P; } diff --git a/src/projections/bonne.cpp b/src/projections/bonne.cpp index 0e9bae79..31f90907 100644 --- a/src/projections/bonne.cpp +++ b/src/projections/bonne.cpp @@ -20,20 +20,25 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY bonne_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double rh, E, c; rh = Q->am1 + Q->m1 - pj_mlfn(lp.phi, E = sin(lp.phi), c = cos(lp.phi), Q->en); - E = c * lp.lam / (rh * sqrt(1. - P->es * E * E)); - xy.x = rh * sin(E); - xy.y = Q->am1 - rh * cos(E); + if (fabs(rh) > EPS10) { + E = c * lp.lam / (rh * sqrt(1. - P->es * E * E)); + xy.x = rh * sin(E); + xy.y = Q->am1 - rh * cos(E); + } else { + xy.x = 0.; + xy.y = 0.; + } return xy; } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY bonne_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double E, rh; @@ -48,7 +53,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP bonne_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double rh; @@ -67,7 +72,7 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP bonne_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double s, rh; @@ -120,15 +125,15 @@ PJ *PROJECTION(bonne) { Q->m1 = pj_mlfn(Q->phi1, Q->am1 = sin(Q->phi1), c = cos(Q->phi1), Q->en); Q->am1 = c / (sqrt(1. - P->es * Q->am1 * Q->am1) * Q->am1); - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = bonne_e_inverse; + P->fwd = bonne_e_forward; } else { if (fabs(Q->phi1) + EPS10 >= M_HALFPI) Q->cphi1 = 0.; else Q->cphi1 = 1. / tan(Q->phi1); - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = bonne_s_inverse; + P->fwd = bonne_s_forward; } return P; } diff --git a/src/projections/calcofi.cpp b/src/projections/calcofi.cpp index e81843b4..57c12dde 100644 --- a/src/projections/calcofi.cpp +++ b/src/projections/calcofi.cpp @@ -35,7 +35,7 @@ whatever ellipsoid is provided. */ #define ROTATION_ANGLE 0.52359877559829882 /*CalCOFI angle of 30 deg in rad */ -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY calcofi_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; double oy; /* pt O y value in Mercator */ double l1; /* l1 and l2 are distances calculated using trig that sum @@ -67,7 +67,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY calcofi_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double oy; double l1; @@ -93,7 +93,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP calcofi_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; double ry; /* y value of point r */ double oymctr; /* Mercator-transformed y value of point O */ @@ -116,7 +116,7 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP calcofi_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double ry; double oymctr; @@ -153,11 +153,11 @@ PJ *PROJECTION(calcofi) { P->over = 1; if (P->es != 0.0) { /* ellipsoid */ - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = calcofi_e_inverse; + P->fwd = calcofi_e_forward; } else { /* sphere */ - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = calcofi_s_inverse; + P->fwd = calcofi_s_forward; } return P; } diff --git a/src/projections/cass.cpp b/src/projections/cass.cpp index ee050548..9eea10c5 100644 --- a/src/projections/cass.cpp +++ b/src/projections/cass.cpp @@ -25,7 +25,7 @@ struct pj_opaque { -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY cass_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ double n, t, a1, c, a2, tn; PJ_XY xy = {0.0, 0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -47,7 +47,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY cass_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0, 0.0}; xy.x = asin (cos (lp.phi) * sin (lp.lam)); xy.y = atan2 (tan (lp.phi), cos (lp.lam)) - P->phi0; @@ -55,7 +55,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP cass_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ double n, t, r, dd, d2, tn, ph1; PJ_LP lp = {0.0, 0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -76,7 +76,7 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP cass_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double dd; lp.phi = asin(sin(dd = xy.y + P->phi0) * cos(xy.x)); @@ -101,8 +101,8 @@ PJ *PROJECTION(cass) { /* Spheroidal? */ if (0==P->es) { - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = cass_s_inverse; + P->fwd = cass_s_forward; return P; } @@ -117,8 +117,8 @@ PJ *PROJECTION(cass) { return pj_default_destructor (P, ENOMEM); static_cast<struct pj_opaque*>(P->opaque)->m0 = pj_mlfn (P->phi0, sin (P->phi0), cos (P->phi0), static_cast<struct pj_opaque*>(P->opaque)->en); - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = cass_e_inverse; + P->fwd = cass_e_forward; return P; } diff --git a/src/projections/cc.cpp b/src/projections/cc.cpp index 559a4f1a..244e185d 100644 --- a/src/projections/cc.cpp +++ b/src/projections/cc.cpp @@ -9,7 +9,7 @@ PROJ_HEAD(cc, "Central Cylindrical") "\n\tCyl, Sph"; #define EPS10 1.e-10 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY cc_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); @@ -21,7 +21,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP cc_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; (void) P; lp.phi = atan(xy.y); @@ -34,8 +34,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(cc) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = cc_s_inverse; + P->fwd = cc_s_forward; return P; } diff --git a/src/projections/ccon.cpp b/src/projections/ccon.cpp index 5f5128cf..e2312c0d 100644 --- a/src/projections/ccon.cpp +++ b/src/projections/ccon.cpp @@ -43,7 +43,7 @@ PROJ_HEAD(ccon, "Central Conic") -static PJ_XY forward (PJ_LP lp, PJ *P) { +static PJ_XY ccon_forward (PJ_LP lp, PJ *P) { PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double r; @@ -56,7 +56,7 @@ static PJ_XY forward (PJ_LP lp, PJ *P) { } -static PJ_LP inverse (PJ_XY xy, PJ *P) { +static PJ_LP ccon_inverse (PJ_XY xy, PJ *P) { PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -100,8 +100,8 @@ PJ *PROJECTION(ccon) { Q->ctgphi1 = Q->cosphi1/Q->sinphi1; - P->inv = inverse; - P->fwd = forward; + P->inv = ccon_inverse; + P->fwd = ccon_forward; return P; } diff --git a/src/projections/cea.cpp b/src/projections/cea.cpp index a1c9c8b5..a7e5fd04 100644 --- a/src/projections/cea.cpp +++ b/src/projections/cea.cpp @@ -17,7 +17,7 @@ PROJ_HEAD(cea, "Equal Area Cylindrical") "\n\tCyl, Sph&Ell\n\tlat_ts="; # define EPS 1e-10 -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY cea_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; xy.x = P->k0 * lp.lam; xy.y = 0.5 * pj_qsfn (sin (lp.phi), P->e, P->one_es) / P->k0; @@ -25,7 +25,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY cea_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; xy.x = P->k0 * lp.lam; xy.y = sin(lp.phi) / P->k0; @@ -33,7 +33,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP cea_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; lp.phi = pj_authlat(asin( 2. * xy.y * P->k0 / static_cast<struct pj_opaque*>(P->opaque)->qp), static_cast<struct pj_opaque*>(P->opaque)->apa); lp.lam = xy.x / P->k0; @@ -41,7 +41,7 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP cea_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double t; @@ -92,11 +92,11 @@ PJ *PROJECTION(cea) { return pj_default_destructor(P, ENOMEM); Q->qp = pj_qsfn(1., P->e, P->one_es); - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = cea_e_inverse; + P->fwd = cea_e_forward; } else { - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = cea_s_inverse; + P->fwd = cea_s_forward; } return P; diff --git a/src/projections/chamb.cpp b/src/projections/chamb.cpp index 33a38781..e6bac22c 100644 --- a/src/projections/chamb.cpp +++ b/src/projections/chamb.cpp @@ -54,7 +54,7 @@ static double lc(projCtx ctx, double b,double c,double a) { } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY chamb_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double sinphi, cosphi, a; @@ -135,7 +135,7 @@ PJ *PROJECTION(chamb) { Q->p.x = Q->c[2].p.x = Q->c[0].p.x + Q->c[2].v.r * cos(Q->beta_0); P->es = 0.; - P->fwd = s_forward; + P->fwd = chamb_s_forward; return P; } diff --git a/src/projections/collg.cpp b/src/projections/collg.cpp index b22e1bf2..40319a51 100644 --- a/src/projections/collg.cpp +++ b/src/projections/collg.cpp @@ -11,7 +11,7 @@ PROJ_HEAD(collg, "Collignon") "\n\tPCyl, Sph"; #define ONEEPS 1.0000001 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY collg_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; if ((xy.y = 1. - sin(lp.phi)) <= 0.) @@ -24,7 +24,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP collg_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; lp.phi = xy.y / FYC - 1.; if (fabs(lp.phi = 1. - lp.phi * lp.phi) < 1.) @@ -46,8 +46,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(collg) { P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = collg_s_inverse; + P->fwd = collg_s_forward; return P; } diff --git a/src/projections/comill.cpp b/src/projections/comill.cpp index 3af19b42..afcfbf7f 100644 --- a/src/projections/comill.cpp +++ b/src/projections/comill.cpp @@ -26,7 +26,7 @@ PROJ_HEAD(comill, "Compact Miller") "\n\tCyl, Sph"; /* Not sure at all of the appropriate number for MAX_ITER... */ #define MAX_ITER 100 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY comill_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double lat_sq; @@ -39,7 +39,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP comill_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double yc, tol, y2, f, fder; int i; @@ -78,8 +78,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(comill) { P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = comill_s_inverse; + P->fwd = comill_s_forward; return P; } diff --git a/src/projections/crast.cpp b/src/projections/crast.cpp index 35272058..cff35472 100644 --- a/src/projections/crast.cpp +++ b/src/projections/crast.cpp @@ -13,7 +13,7 @@ PROJ_HEAD(crast, "Craster Parabolic (Putnins P4)") "\n\tPCyl, Sph"; #define THIRD 0.333333333333333333 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY crast_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; lp.phi *= THIRD; @@ -23,7 +23,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP crast_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; (void) P; lp.phi = 3. * asin(xy.y * RYM); @@ -34,8 +34,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(crast) { P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = crast_s_inverse; + P->fwd = crast_s_forward; return P; } diff --git a/src/projections/denoy.cpp b/src/projections/denoy.cpp index 1560ad6b..5f736a40 100644 --- a/src/projections/denoy.cpp +++ b/src/projections/denoy.cpp @@ -13,7 +13,7 @@ PROJ_HEAD(denoy, "Denoyer Semi-Elliptical") "\n\tPCyl, no inv, Sph"; #define D5 0.03 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY denoy_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0, 0.0}; (void) P; xy.y = lp.phi; @@ -27,7 +27,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ *PROJECTION(denoy) { P->es = 0.0; - P->fwd = s_forward; + P->fwd = denoy_s_forward; return P; } diff --git a/src/projections/eck1.cpp b/src/projections/eck1.cpp index 3a19796e..55944952 100644 --- a/src/projections/eck1.cpp +++ b/src/projections/eck1.cpp @@ -9,7 +9,7 @@ PROJ_HEAD(eck1, "Eckert I") "\n\tPCyl, Sph"; #define RP 0.31830988618379067154 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY eck1_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; @@ -20,7 +20,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP eck1_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; (void) P; @@ -34,8 +34,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(eck1) { P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = eck1_s_inverse; + P->fwd = eck1_s_forward; return P ; diff --git a/src/projections/eck2.cpp b/src/projections/eck2.cpp index f019fdab..27b94aed 100644 --- a/src/projections/eck2.cpp +++ b/src/projections/eck2.cpp @@ -13,7 +13,7 @@ PROJ_HEAD(eck2, "Eckert II") "\n\tPCyl, Sph"; #define ONEEPS 1.0000001 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY eck2_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; @@ -25,7 +25,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP eck2_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; (void) P; @@ -49,8 +49,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(eck2) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = eck2_s_inverse; + P->fwd = eck2_s_forward; return P; } diff --git a/src/projections/eck3.cpp b/src/projections/eck3.cpp index 6777c765..dd04fb39 100644 --- a/src/projections/eck3.cpp +++ b/src/projections/eck3.cpp @@ -18,7 +18,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY eck3_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -28,7 +28,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP eck3_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double denominator; @@ -45,8 +45,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ static PJ *setup(PJ *P) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = eck3_s_inverse; + P->fwd = eck3_s_forward; return P; } diff --git a/src/projections/eck4.cpp b/src/projections/eck4.cpp index 7f8203b2..df2caf42 100644 --- a/src/projections/eck4.cpp +++ b/src/projections/eck4.cpp @@ -16,7 +16,7 @@ PROJ_HEAD(eck4, "Eckert IV") "\n\tPCyl, Sph"; #define NITER 6 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY eck4_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double p, V, s, c; int i; @@ -44,7 +44,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP eck4_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double c; @@ -57,8 +57,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(eck4) { P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = eck4_s_inverse; + P->fwd = eck4_s_forward; return P; } diff --git a/src/projections/eck5.cpp b/src/projections/eck5.cpp index 40e9d3bb..bf0e6a42 100644 --- a/src/projections/eck5.cpp +++ b/src/projections/eck5.cpp @@ -13,7 +13,7 @@ PROJ_HEAD(eck5, "Eckert V") "\n\tPCyl, Sph"; #define RYF 1.13375401361911319568 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY eck5_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; xy.x = XF * (1. + cos(lp.phi)) * lp.lam; @@ -23,7 +23,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP eck5_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; (void) P; lp.lam = RXF * xy.x / (1. + cos( lp.phi = RYF * xy.y)); @@ -34,8 +34,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(eck5) { P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = eck5_s_inverse; + P->fwd = eck5_s_forward; return P; } diff --git a/src/projections/eqc.cpp b/src/projections/eqc.cpp index eb021eac..194625ef 100644 --- a/src/projections/eqc.cpp +++ b/src/projections/eqc.cpp @@ -16,7 +16,7 @@ PROJ_HEAD(eqc, "Equidistant Cylindrical (Plate Carree)") "\n\tCyl, Sph\n\tlat_ts=[, lat_0=0]"; -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY eqc_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -27,7 +27,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP eqc_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -46,8 +46,8 @@ PJ *PROJECTION(eqc) { if ((Q->rc = cos(pj_param(P->ctx, P->params, "rlat_ts").f)) <= 0.) return pj_default_destructor (P, PJD_ERR_LAT_TS_LARGER_THAN_90); - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = eqc_s_inverse; + P->fwd = eqc_s_forward; P->es = 0.; return P; diff --git a/src/projections/eqdc.cpp b/src/projections/eqdc.cpp index d175d4a1..e050a593 100644 --- a/src/projections/eqdc.cpp +++ b/src/projections/eqdc.cpp @@ -25,7 +25,7 @@ PROJ_HEAD(eqdc, "Equidistant Conic") # define EPS10 1.e-10 -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY eqdc_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -38,7 +38,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP eqdc_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -84,12 +84,14 @@ PJ *PROJECTION(eqdc) { Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f; + if (fabs(Q->phi1) > M_HALFPI || fabs(Q->phi2) > M_HALFPI) + return destructor(P, PJD_ERR_LAT_LARGER_THAN_90); if (fabs(Q->phi1 + Q->phi2) < EPS10) - return pj_default_destructor (P, PJD_ERR_CONIC_LAT_EQUAL); + return destructor (P, PJD_ERR_CONIC_LAT_EQUAL); if (!(Q->en = pj_enfn(P->es))) - return pj_default_destructor(P, ENOMEM); + return destructor(P, ENOMEM); Q->n = sinphi = sin(Q->phi1); cosphi = cos(Q->phi1); @@ -104,6 +106,10 @@ PJ *PROJECTION(eqdc) { cosphi = cos(Q->phi2); Q->n = (m1 - pj_msfn(sinphi, cosphi, P->es)) / (pj_mlfn(Q->phi2, sinphi, cosphi, Q->en) - ml1); + if (Q->n == 0) { + // Not quite, but es is very close to 1... + return destructor(P, PJD_ERR_INVALID_ECCENTRICITY); + } } Q->c = ml1 + m1 / Q->n; Q->rho0 = Q->c - pj_mlfn(P->phi0, sin(P->phi0), @@ -115,8 +121,8 @@ PJ *PROJECTION(eqdc) { Q->rho0 = Q->c - P->phi0; } - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = eqdc_e_inverse; + P->fwd = eqdc_e_forward; return P; } diff --git a/src/projections/eqearth.cpp b/src/projections/eqearth.cpp index dc58eed9..832c9444 100644 --- a/src/projections/eqearth.cpp +++ b/src/projections/eqearth.cpp @@ -26,7 +26,7 @@ PROJ_HEAD(eqearth, "Equal Earth") "\n\tPCyl, Sph&Ell"; #define A2 -0.081106 #define A3 0.000893 #define A4 0.003796 -#define M (sqrt(3) / 2.0) +#define M (sqrt(3.0) / 2.0) #define MAX_Y 1.3173627591574 /* 90° latitude on a sphere with radius 1 */ #define EPS 1e-11 @@ -40,7 +40,7 @@ struct pj_opaque { }; } // anonymous namespace -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal/spheroidal, forward */ +static PJ_XY eqearth_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal/spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double sbeta; @@ -74,7 +74,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal/spheroidal, } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal/spheroidal, inverse */ +static PJ_LP eqearth_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal/spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double yc, y2, y6; @@ -148,8 +148,8 @@ PJ *PROJECTION(eqearth) { return pj_default_destructor (P, ENOMEM); P->opaque = Q; P->destructor = destructor; - P->fwd = e_forward; - P->inv = e_inverse; + P->fwd = eqearth_e_forward; + P->inv = eqearth_e_inverse; Q->rqda = 1.0; /* Ellipsoidal case */ diff --git a/src/projections/fahey.cpp b/src/projections/fahey.cpp index ba8cb8f9..9561217a 100644 --- a/src/projections/fahey.cpp +++ b/src/projections/fahey.cpp @@ -10,7 +10,7 @@ PROJ_HEAD(fahey, "Fahey") "\n\tPcyl, Sph"; #define TOL 1e-6 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY fahey_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; @@ -21,7 +21,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP fahey_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; (void) P; @@ -35,8 +35,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(fahey) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = fahey_s_inverse; + P->fwd = fahey_s_forward; return P; } diff --git a/src/projections/fouc_s.cpp b/src/projections/fouc_s.cpp index e91f41c3..29d6437d 100644 --- a/src/projections/fouc_s.cpp +++ b/src/projections/fouc_s.cpp @@ -18,7 +18,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY fouc_s_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double t; @@ -30,7 +30,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP fouc_s_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double V; @@ -66,7 +66,7 @@ PJ *PROJECTION(fouc_s) { Q->n1 = 1. - Q->n; P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = fouc_s_s_inverse; + P->fwd = fouc_s_s_forward; return P; } diff --git a/src/projections/gall.cpp b/src/projections/gall.cpp index 8f1ca1f8..091c75d7 100644 --- a/src/projections/gall.cpp +++ b/src/projections/gall.cpp @@ -13,7 +13,7 @@ PROJ_HEAD(gall, "Gall (Gall Stereographic)") "\n\tCyl, Sph"; #define RXF 1.41421356237309504880 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY gall_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; @@ -24,7 +24,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP gall_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; (void) P; @@ -38,8 +38,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(gall) { P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = gall_s_inverse; + P->fwd = gall_s_forward; return P; } diff --git a/src/projections/geos.cpp b/src/projections/geos.cpp index cdb0244a..5b3e594c 100644 --- a/src/projections/geos.cpp +++ b/src/projections/geos.cpp @@ -52,7 +52,7 @@ struct pj_opaque { PROJ_HEAD(geos, "Geostationary Satellite View") "\n\tAzi, Sph&Ell\n\th="; -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY geos_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double Vx, Vy, Vz, tmp; @@ -82,7 +82,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY geos_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double r, Vx, Vy, Vz, tmp; @@ -118,7 +118,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP geos_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double Vx, Vy, Vz, a, b, det, k; @@ -155,7 +155,7 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP geos_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double Vx, Vy, Vz, a, b, det, k; @@ -202,8 +202,7 @@ PJ *PROJECTION(geos) { return pj_default_destructor (P, ENOMEM); P->opaque = Q; - if ((Q->h = pj_param(P->ctx, P->params, "dh").f) <= 0.) - return pj_default_destructor (P, PJD_ERR_H_LESS_THAN_ZERO); + Q->h = pj_param(P->ctx, P->params, "dh").f; sweep_axis = pj_param(P->ctx, P->params, "ssweep").s; if (sweep_axis == nullptr) @@ -220,18 +219,20 @@ PJ *PROJECTION(geos) { } Q->radius_g_1 = Q->h / P->a; + if ( Q->radius_g_1 <= 0 || Q->radius_g_1 > 1e10 ) + return pj_default_destructor (P, PJD_ERR_INVALID_H); Q->radius_g = 1. + Q->radius_g_1; Q->C = Q->radius_g * Q->radius_g - 1.0; if (P->es != 0.0) { Q->radius_p = sqrt (P->one_es); Q->radius_p2 = P->one_es; Q->radius_p_inv2 = P->rone_es; - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = geos_e_inverse; + P->fwd = geos_e_forward; } else { Q->radius_p = Q->radius_p2 = Q->radius_p_inv2 = 1.0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = geos_s_inverse; + P->fwd = geos_s_forward; } return P; diff --git a/src/projections/gins8.cpp b/src/projections/gins8.cpp index 6f499889..73f00d6f 100644 --- a/src/projections/gins8.cpp +++ b/src/projections/gins8.cpp @@ -10,7 +10,7 @@ PROJ_HEAD(gins8, "Ginsburg VIII (TsNIIGAiK)") "\n\tPCyl, Sph, no inv"; #define C12 0.08333333333333333 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY gins8_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double t = lp.phi * lp.phi; (void) P; @@ -27,7 +27,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ *PROJECTION(gins8) { P->es = 0.0; P->inv = nullptr; - P->fwd = s_forward; + P->fwd = gins8_s_forward; return P; } diff --git a/src/projections/gn_sinu.cpp b/src/projections/gn_sinu.cpp index 3a591669..84883cbc 100644 --- a/src/projections/gn_sinu.cpp +++ b/src/projections/gn_sinu.cpp @@ -23,7 +23,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY gn_sinu_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; double s, c; @@ -33,7 +33,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP gn_sinu_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; double s; @@ -50,7 +50,7 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY gn_sinu_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -80,7 +80,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP gn_sinu_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -109,8 +109,8 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor static void setup(PJ *P) { struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = gn_sinu_s_inverse; + P->fwd = gn_sinu_s_forward; Q->C_x = (Q->C_y = sqrt((Q->m + 1.) / Q->n))/(Q->m + 1.); } @@ -127,8 +127,8 @@ PJ *PROJECTION(sinu) { return pj_default_destructor (P, ENOMEM); if (P->es != 0.0) { - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = gn_sinu_e_inverse; + P->fwd = gn_sinu_e_forward; } else { Q->n = 1.; Q->m = 0.; diff --git a/src/projections/gnom.cpp b/src/projections/gnom.cpp index bf454ba9..f7cb2635 100644 --- a/src/projections/gnom.cpp +++ b/src/projections/gnom.cpp @@ -29,7 +29,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY gnom_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double coslam, cosphi, sinphi; @@ -77,7 +77,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP gnom_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double rh, cosz, sinz; @@ -139,8 +139,8 @@ PJ *PROJECTION(gnom) { Q->cosph0 = cos(P->phi0); } - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = gnom_s_inverse; + P->fwd = gnom_s_forward; P->es = 0.; return P; diff --git a/src/projections/goode.cpp b/src/projections/goode.cpp index 802df90c..c716649d 100644 --- a/src/projections/goode.cpp +++ b/src/projections/goode.cpp @@ -21,7 +21,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY goode_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -35,7 +35,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP goode_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -77,8 +77,8 @@ PJ *PROJECTION(goode) { if (!(Q->sinu = pj_sinu(Q->sinu)) || !(Q->moll = pj_moll(Q->moll))) return destructor (P, ENOMEM); - P->fwd = s_forward; - P->inv = s_inverse; + P->fwd = goode_s_forward; + P->inv = goode_s_inverse; return P; } diff --git a/src/projections/gstmerc.cpp b/src/projections/gstmerc.cpp index 735d39e5..808d9ef7 100644 --- a/src/projections/gstmerc.cpp +++ b/src/projections/gstmerc.cpp @@ -22,7 +22,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY gstmerc_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double L, Ls, sinLs1, Ls1; @@ -38,7 +38,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP gstmerc_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double L, LC, sinC; @@ -68,8 +68,8 @@ PJ *PROJECTION(gstmerc) { Q->XS = 0; Q->YS = -1.0 * Q->n2 * Q->phic; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = gstmerc_s_inverse; + P->fwd = gstmerc_s_forward; return P; } diff --git a/src/projections/hammer.cpp b/src/projections/hammer.cpp index aa7d1ba9..56bdf74e 100644 --- a/src/projections/hammer.cpp +++ b/src/projections/hammer.cpp @@ -19,19 +19,26 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY hammer_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cosphi, d; - d = sqrt(2./(1. + (cosphi = cos(lp.phi)) * cos(lp.lam *= Q->w))); + cosphi = cos(lp.phi); + lp.lam *= Q->w; + double denom = 1. + cosphi * cos(lp.lam); + if( denom == 0.0 ) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return proj_coord_error().xy; + } + d = sqrt(2./denom); xy.x = Q->m * d * cosphi * sin(lp.lam); xy.y = Q->rm * d * sin(lp.phi); return xy; } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP hammer_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double z; @@ -70,8 +77,8 @@ PJ *PROJECTION(hammer) { Q->m /= Q->w; P->es = 0.; - P->fwd = s_forward; - P->inv = s_inverse; + P->fwd = hammer_s_forward; + P->inv = hammer_s_inverse; return P; } diff --git a/src/projections/hatano.cpp b/src/projections/hatano.cpp index b2ef6c6f..6c125d2e 100644 --- a/src/projections/hatano.cpp +++ b/src/projections/hatano.cpp @@ -22,7 +22,7 @@ PROJ_HEAD(hatano, "Hatano Asymmetrical Equal Area") "\n\tPCyl, Sph"; #define RXC 1.17647058823529411764 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY hatano_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double th1, c; int i; @@ -40,7 +40,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP hatano_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double th; @@ -76,8 +76,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(hatano) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = hatano_s_inverse; + P->fwd = hatano_s_forward; return P; } diff --git a/src/projections/healpix.cpp b/src/projections/healpix.cpp index 8e4846ed..515f4f6f 100644 --- a/src/projections/healpix.cpp +++ b/src/projections/healpix.cpp @@ -33,7 +33,6 @@ #include <errno.h> #include <math.h> -#include "proj_internal.h" #include "proj.h" #include "proj_internal.h" @@ -282,7 +281,7 @@ static PJ_XY healpix_sphere(PJ_LP lp) { /** * Return the inverse of healpix_sphere(). **/ -static PJ_LP healpix_sphere_inverse(PJ_XY xy) { +static PJ_LP healpix_spherhealpix_e_inverse(PJ_XY xy) { PJ_LP lp; double x = xy.x; double y = xy.y; @@ -533,7 +532,7 @@ static PJ_LP s_healpix_inverse(PJ_XY xy, PJ *P) { /* sphere */ pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); return lp; } - return healpix_sphere_inverse(xy); + return healpix_spherhealpix_e_inverse(xy); } @@ -547,7 +546,7 @@ static PJ_LP e_healpix_inverse(PJ_XY xy, PJ *P) { /* ellipsoid */ pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); return lp; } - lp = healpix_sphere_inverse(xy); + lp = healpix_spherhealpix_e_inverse(xy); lp.phi = auth_lat(P, lp.phi, 1); return lp; } @@ -582,7 +581,7 @@ static PJ_LP s_rhealpix_inverse(PJ_XY xy, PJ *P) { /* sphere */ return lp; } xy = combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 1); - return healpix_sphere_inverse(xy); + return healpix_spherhealpix_e_inverse(xy); } @@ -598,7 +597,7 @@ static PJ_LP e_rhealpix_inverse(PJ_XY xy, PJ *P) { /* ellipsoid */ return lp; } xy = combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 1); - lp = healpix_sphere_inverse(xy); + lp = healpix_spherhealpix_e_inverse(xy); lp.phi = auth_lat(P, lp.phi, 1); return lp; } diff --git a/src/projections/igh.cpp b/src/projections/igh.cpp index a8efbb9d..8a41cea3 100644 --- a/src/projections/igh.cpp +++ b/src/projections/igh.cpp @@ -41,7 +41,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY igh_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); int z; @@ -74,10 +74,10 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP igh_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); - const double y90 = Q->dy0 + sqrt(2); /* lt=90 corresponds to y=y0+sqrt(2) */ + const double y90 = Q->dy0 + sqrt(2.0); /* lt=90 corresponds to y=y0+sqrt(2) */ int z = 0; if (xy.y > y90+EPSLN || xy.y < -y90+EPSLN) /* 0 */ @@ -219,8 +219,8 @@ PJ *PROJECTION(igh) { SETUP(11, moll, d20, -Q->dy0, d20); SETUP(12, moll, d140, -Q->dy0, d140); - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = igh_s_inverse; + P->fwd = igh_s_forward; P->destructor = destructor; P->es = 0.; diff --git a/src/projections/imw_p.cpp b/src/projections/imw_p.cpp index 723fcc48..ee206091 100644 --- a/src/projections/imw_p.cpp +++ b/src/projections/imw_p.cpp @@ -97,14 +97,14 @@ static PJ_XY loc_for(PJ_LP lp, PJ *P, double *yc) { } -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY imw_p_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ double yc; PJ_XY xy = loc_for(lp, P, &yc); return (xy); } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP imw_p_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); PJ_XY t; @@ -116,15 +116,25 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ lp.lam = xy.x / cos(lp.phi); do { t = loc_for(lp, P, &yc); - lp.phi = ((lp.phi - Q->phi_1) * (xy.y - yc) / (t.y - yc)) + Q->phi_1; - lp.lam = lp.lam * xy.x / t.x; + const double denom = t.y - yc; + if( denom != 0 || fabs(t.y - xy.y) > TOL ) + { + if( denom == 0 ) { + proj_errno_set(P, PJD_ERR_NON_CONVERGENT); + return proj_coord_error().lp; + } + lp.phi = ((lp.phi - Q->phi_1) * (xy.y - yc) / denom) + Q->phi_1; + } + if( t.x != 0 && fabs(t.x - xy.x) > TOL ) + lp.lam = lp.lam * xy.x / t.x; i ++; } while (i < N_MAX_ITER && (fabs(t.x - xy.x) > TOL || fabs(t.y - xy.y) > TOL)); if( i == N_MAX_ITER ) { - lp.lam = lp.phi = HUGE_VAL; + proj_errno_set(P, PJD_ERR_NON_CONVERGENT); + return proj_coord_error().lp; } return lp; @@ -209,8 +219,8 @@ PJ *PROJECTION(imw_p) { Q->Pp = (m2 * x1 - m1 * x2) * t; Q->Qp = (x2 - x1) * t; - P->fwd = e_forward; - P->inv = e_inverse; + P->fwd = imw_p_e_forward; + P->inv = imw_p_e_inverse; P->destructor = destructor; return P; diff --git a/src/projections/isea.cpp b/src/projections/isea.cpp index 3a0a0a48..c22e143d 100644 --- a/src/projections/isea.cpp +++ b/src/projections/isea.cpp @@ -10,11 +10,12 @@ #include <stdlib.h> #include <string.h> +#include <limits> + #define PJ_LIB__ -#include "proj_internal.h" -#include "proj_math.h" #include "proj.h" #include "proj_internal.h" +#include "proj_math.h" #define DEG36 0.62831853071795864768 #define DEG72 1.25663706143591729537 @@ -89,6 +90,9 @@ static void hexbin2(double width, double x, double y, long *i, long *j) { y = y - x / 2.0; /* adjustment for rotated X */ /* adjust for actual hexwidth */ + if( width == 0 ) { + throw "Division by zero"; + } x /= width; y /= width; @@ -100,6 +104,10 @@ static void hexbin2(double width, double x, double y, long *i, long *j) { iy = lround(ry); rz = floor(z + 0.5); iz = lround(rz); + if( fabs((double)ix + iy) > std::numeric_limits<int>::max() || + fabs((double)ix + iy + iz) > std::numeric_limits<int>::max() ) { + throw "Integer overflow"; + } s = ix + iy + iz; @@ -764,11 +772,18 @@ static int isea_dddi(struct isea_dgg *g, int quad, struct isea_pt *pt, } /* todo might want to do this as an iterated loop */ if (g->aperture >0) { - sidelength = lround(pow(g->aperture, g->resolution / 2.0)); + double sidelengthDouble = pow(g->aperture, g->resolution / 2.0); + if( fabs(sidelengthDouble) > std::numeric_limits<int>::max() ) { + throw "Integer overflow"; + } + sidelength = lround(sidelengthDouble); } else { sidelength = g->resolution; } + if( sidelength == 0 ) { + throw "Division by zero"; + } hexwidth = 1.0 / sidelength; v = *pt; @@ -847,7 +862,7 @@ static long isea_disn(struct isea_dgg *g, int quad, struct isea_pt *di) { return g->serial; } /* hexes in a quad */ - hexes = lround(pow(g->aperture, g->resolution)); + hexes = lround(pow(static_cast<double>(g->aperture), static_cast<double>(g->resolution))); if (quad == 11) { g->serial = 1 + 10 * hexes + 1; return g->serial; @@ -883,6 +898,10 @@ static int isea_hex(struct isea_dgg *g, int tri, quad = isea_ptdi(g, tri, pt, &v); + if( v.x < (INT_MIN >> 4) || v.x > (INT_MAX >> 4) ) + { + throw "Invalid shift"; + } hex->x = ((int)v.x << 4) + quad; hex->y = v.y; @@ -995,7 +1014,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY isea_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); struct isea_pt out; @@ -1004,7 +1023,12 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ in.lon = lp.lam; in.lat = lp.phi; - out = isea_forward(&Q->dgg, &in); + try { + out = isea_forward(&Q->dgg, &in); + } catch( const char* ) { + proj_errno_set(P, PJD_ERR_NON_CONVERGENT); + return proj_coord_error().xy; + } xy.x = out.x; xy.y = out.y; @@ -1021,7 +1045,7 @@ PJ *PROJECTION(isea) { P->opaque = Q; - P->fwd = s_forward; + P->fwd = isea_s_forward; isea_grid_init(&Q->dgg); Q->dgg.output = ISEA_PLANE; @@ -1051,14 +1075,6 @@ PJ *PROJECTION(isea) { Q->dgg.o_lat = pj_param(P->ctx,P->params, "rlat_0").f; } - if (pj_param(P->ctx,P->params, "taperture").i) { - Q->dgg.aperture = pj_param(P->ctx,P->params, "iaperture").i; - } - - if (pj_param(P->ctx,P->params, "tresolution").i) { - Q->dgg.resolution = pj_param(P->ctx,P->params, "iresolution").i; - } - opt = pj_param(P->ctx,P->params, "smode").s; if (opt) { if (!strcmp(opt, "plane")) { diff --git a/src/projections/krovak.cpp b/src/projections/krovak.cpp index 591f8dcc..98f09199 100644 --- a/src/projections/krovak.cpp +++ b/src/projections/krovak.cpp @@ -103,7 +103,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY krovak_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); PJ_XY xy = {0.0,0.0}; @@ -115,7 +115,14 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forwar deltav = -lp.lam * Q->alpha; s = asin(cos(Q->ad) * sin(u) + sin(Q->ad) * cos(u) * cos(deltav)); - d = asin(cos(u) * sin(deltav) / cos(s)); + const double cos_s = cos(s); + if( cos_s < 1e-12 ) + { + xy.x = 0; + xy.y = 0; + return xy; + } + d = asin(cos(u) * sin(deltav) / cos_s); eps = Q->n * d; rho = Q->rho0 * pow(tan(S0 / 2. + M_PI_4) , Q->n) / pow(tan(s / 2. + M_PI_4) , Q->n); @@ -130,7 +137,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forwar } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP krovak_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); PJ_LP lp = {0.0,0.0}; @@ -148,7 +155,12 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, invers eps = atan2(xy.y, xy.x); d = eps / sin(S0); - s = 2. * (atan( pow(Q->rho0 / rho, 1. / Q->n) * tan(S0 / 2. + M_PI_4)) - M_PI_4); + if( rho == 0.0 ) { + s = M_PI_2; + } + else { + s = 2. * (atan( pow(Q->rho0 / rho, 1. / Q->n) * tan(S0 / 2. + M_PI_4)) - M_PI_4); + } u = asin(cos(Q->ad) * sin(s) - sin(Q->ad) * cos(s) * cos(d)); deltav = asin(cos(s) * sin(d) / cos(u)); @@ -210,14 +222,18 @@ PJ *PROJECTION(krovak) { Q->alpha = sqrt(1. + (P->es * pow(cos(P->phi0), 4)) / (1. - P->es)); u0 = asin(sin(P->phi0) / Q->alpha); g = pow( (1. + P->e * sin(P->phi0)) / (1. - P->e * sin(P->phi0)) , Q->alpha * P->e / 2. ); - Q->k = tan( u0 / 2. + M_PI_4) / pow (tan(P->phi0 / 2. + M_PI_4) , Q->alpha) * g; + double tan_half_phi0_plus_pi_4 = tan(P->phi0 / 2. + M_PI_4); + if( tan_half_phi0_plus_pi_4 == 0.0 ) { + return pj_default_destructor(P, PJD_ERR_INVALID_ARG); + } + Q->k = tan( u0 / 2. + M_PI_4) / pow (tan_half_phi0_plus_pi_4 , Q->alpha) * g; n0 = sqrt(1. - P->es) / (1. - P->es * pow(sin(P->phi0), 2)); Q->n = sin(S0); Q->rho0 = P->k0 * n0 / tan(S0); Q->ad = M_PI_2 - UQ; - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = krovak_e_inverse; + P->fwd = krovak_e_forward; return P; } diff --git a/src/projections/labrd.cpp b/src/projections/labrd.cpp index 85ab3ddd..21d9099f 100644 --- a/src/projections/labrd.cpp +++ b/src/projections/labrd.cpp @@ -16,7 +16,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY labrd_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double V1, V2, ps, sinps, cosps, sinps2, cosps2; @@ -49,7 +49,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP labrd_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); /* t = 0.0 optimization is to avoid a false positive cppcheck warning */ @@ -130,8 +130,8 @@ PJ *PROJECTION(labrd) { Q->Cc = 3. * (Q->Ca * Q->Ca - Q->Cb * Q->Cb); Q->Cd = 6. * Q->Ca * Q->Cb; - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = labrd_e_inverse; + P->fwd = labrd_e_forward; return P; } diff --git a/src/projections/laea.cpp b/src/projections/laea.cpp index 22fb1691..8a23c504 100644 --- a/src/projections/laea.cpp +++ b/src/projections/laea.cpp @@ -32,7 +32,7 @@ struct pj_opaque { #define EPS10 1.e-10 -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY laea_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double coslam, sinlam, sinphi, q, sinb=0.0, cosb=0.0, b=0.0; @@ -94,7 +94,7 @@ eqcon: } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY laea_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double coslam, cosphi, sinphi; @@ -136,7 +136,7 @@ oblcon: } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP laea_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cCe, sCe, q, rho, ab=0.0; @@ -185,7 +185,7 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP laea_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cosz=0.0, rh, sinz=0.0; @@ -248,6 +248,9 @@ PJ *PROJECTION(laea) { P->destructor = destructor; t = fabs(P->phi0); + if (t > M_HALFPI + EPS10 ) { + return destructor(P, PJD_ERR_LAT_LARGER_THAN_90); + } if (fabs(t - M_HALFPI) < EPS10) Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; else if (fabs(t) < EPS10) @@ -284,15 +287,15 @@ PJ *PROJECTION(laea) { Q->xmf *= Q->dd; break; } - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = laea_e_inverse; + P->fwd = laea_e_forward; } else { if (Q->mode == OBLIQ) { Q->sinb1 = sin(P->phi0); Q->cosb1 = cos(P->phi0); } - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = laea_s_inverse; + P->fwd = laea_s_forward; } return P; diff --git a/src/projections/lagrng.cpp b/src/projections/lagrng.cpp index 65686584..d37a00e6 100644 --- a/src/projections/lagrng.cpp +++ b/src/projections/lagrng.cpp @@ -21,17 +21,17 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY lagrng_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double v, c; - if (fabs(fabs(lp.phi) - M_HALFPI) < TOL) { + const double sin_phi = sin(lp.phi); + if (fabs(fabs(sin_phi) - 1) < TOL) { xy.x = 0; xy.y = lp.phi < 0 ? -2. : 2.; } else { - lp.phi = sin(lp.phi); - v = Q->a1 * pow((1. + lp.phi)/(1. - lp.phi), Q->hrw); + v = Q->a1 * pow((1. + sin_phi)/(1. - sin_phi), Q->hrw); lp.lam *= Q->rw; c = 0.5 * (v + 1./v) + cos(lp.lam); if (c < TOL) { @@ -45,7 +45,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP lagrng_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double c, x2, y2p, y2m; @@ -70,7 +70,7 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(lagrng) { - double phi1; + double sin_phi1; struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); @@ -85,16 +85,16 @@ PJ *PROJECTION(lagrng) { Q->hw = 0.5 * Q->w; Q->rw = 1. / Q->w; Q->hrw = 0.5 * Q->rw; - phi1 = sin(pj_param(P->ctx, P->params, "rlat_1").f); - if (fabs(fabs(phi1) - 1.) < TOL) + sin_phi1 = sin(pj_param(P->ctx, P->params, "rlat_1").f); + if (fabs(fabs(sin_phi1) - 1.) < TOL) return pj_default_destructor(P, PJD_ERR_LAT_LARGER_THAN_90); - Q->a1 = pow((1. - phi1)/(1. + phi1), Q->hrw); + Q->a1 = pow((1. - sin_phi1)/(1. + sin_phi1), Q->hrw); Q->a2 = Q->a1 * Q->a1; P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = lagrng_s_inverse; + P->fwd = lagrng_s_forward; return P; } diff --git a/src/projections/larr.cpp b/src/projections/larr.cpp index bab1dbf4..33fbd94c 100644 --- a/src/projections/larr.cpp +++ b/src/projections/larr.cpp @@ -10,7 +10,7 @@ PROJ_HEAD(larr, "Larrivee") "\n\tMisc Sph, no inv"; #define SIXTH .16666666666666666 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY larr_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; @@ -23,7 +23,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ *PROJECTION(larr) { P->es = 0; - P->fwd = s_forward; + P->fwd = larr_s_forward; return P; } diff --git a/src/projections/lask.cpp b/src/projections/lask.cpp index c4c6734d..80e50522 100644 --- a/src/projections/lask.cpp +++ b/src/projections/lask.cpp @@ -17,7 +17,7 @@ PROJ_HEAD(lask, "Laskowski") "\n\tMisc Sph, no inv"; #define b05 -0.0491032 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY lask_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double l2, p2; (void) P; @@ -33,7 +33,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ *PROJECTION(lask) { - P->fwd = s_forward; + P->fwd = lask_s_forward; P->es = 0.; return P; diff --git a/src/projections/latlong.cpp b/src/projections/latlong.cpp index 970c4893..2c98a4cd 100644 --- a/src/projections/latlong.cpp +++ b/src/projections/latlong.cpp @@ -30,7 +30,6 @@ /* very loosely based upon DMA code by Bradford W. Drew */ #define PJ_LIB__ #include "proj_internal.h" -#include "proj_internal.h" PROJ_HEAD(lonlat, "Lat/long (Geodetic)") "\n\t"; PROJ_HEAD(latlon, "Lat/long (Geodetic alias)") "\n\t"; diff --git a/src/projections/lcc.cpp b/src/projections/lcc.cpp index a1fe79a9..beb2efd1 100644 --- a/src/projections/lcc.cpp +++ b/src/projections/lcc.cpp @@ -20,7 +20,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY lcc_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0., 0.}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double rho; @@ -43,7 +43,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP lcc_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0., 0.}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double rho; @@ -94,6 +94,8 @@ PJ *PROJECTION(lcc) { if (!pj_param(P->ctx, P->params, "tlat_0").i) P->phi0 = Q->phi1; } + if (fabs(Q->phi1) > M_HALFPI || fabs(Q->phi2) > M_HALFPI) + return pj_default_destructor(P, PJD_ERR_LAT_LARGER_THAN_90); if (fabs(Q->phi1 + Q->phi2) < EPS10) return pj_default_destructor(P, PJD_ERR_CONIC_LAT_EQUAL); @@ -105,15 +107,34 @@ PJ *PROJECTION(lcc) { m1 = pj_msfn(sinphi, cosphi, P->es); ml1 = pj_tsfn(Q->phi1, sinphi, P->e); + if( ml1 == 0 ) { + return pj_default_destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); + } if (secant) { /* secant cone */ sinphi = sin(Q->phi2); Q->n = log(m1 / pj_msfn(sinphi, cos(Q->phi2), P->es)); - Q->n /= log(ml1 / pj_tsfn(Q->phi2, sinphi, P->e)); + if (Q->n == 0) { + // 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); + } + const double denom = log(ml1 / ml2); + if( denom == 0 ) { + // Not quite, but es is very close to 1... + return pj_default_destructor(P, PJD_ERR_INVALID_ECCENTRICITY); + } + Q->n /= denom; } Q->c = (Q->rho0 = m1 * pow(ml1, -Q->n) / Q->n); Q->rho0 *= (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) ? 0. : pow(pj_tsfn(P->phi0, sin(P->phi0), P->e), Q->n); } else { + if( fabs(cosphi) < EPS10 || fabs(cos(Q->phi2)) < EPS10 ) { + return pj_default_destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); + } if (secant) Q->n = log(cosphi / cos(Q->phi2)) / log(tan(M_FORTPI + .5 * Q->phi2) / @@ -123,8 +144,8 @@ PJ *PROJECTION(lcc) { Q->c * pow(tan(M_FORTPI + .5 * P->phi0), -Q->n); } - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = lcc_e_inverse; + P->fwd = lcc_e_forward; return P; } diff --git a/src/projections/lcca.cpp b/src/projections/lcca.cpp index d4dc8641..11ecb29c 100644 --- a/src/projections/lcca.cpp +++ b/src/projections/lcca.cpp @@ -80,7 +80,7 @@ static double fSp(double S, double C) { /* deriv of fs */ } -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY lcca_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double S, r, dr; @@ -94,7 +94,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP lcca_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double theta, dr, S, dif; @@ -156,8 +156,8 @@ PJ *PROJECTION(lcca) { Q->r0 = N0 / tan0; Q->C = 1. / (6. * R0 * N0); - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = lcca_e_inverse; + P->fwd = lcca_e_forward; P->destructor = destructor; return P; diff --git a/src/projections/loxim.cpp b/src/projections/loxim.cpp index 2a780a9e..2ee88037 100644 --- a/src/projections/loxim.cpp +++ b/src/projections/loxim.cpp @@ -19,7 +19,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY loxim_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -37,7 +37,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP loxim_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -69,8 +69,8 @@ PJ *PROJECTION(loxim) { Q->tanphi1 = tan(M_FORTPI + 0.5 * Q->phi1); - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = loxim_s_inverse; + P->fwd = loxim_s_forward; P->es = 0.; return P; diff --git a/src/projections/lsat.cpp b/src/projections/lsat.cpp index 5b7520d3..f6114485 100644 --- a/src/projections/lsat.cpp +++ b/src/projections/lsat.cpp @@ -44,7 +44,7 @@ static void seraz0(double lam, double mult, PJ *P) { } -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY lsat_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); int l, nn; @@ -107,12 +107,11 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP lsat_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); int nn; double lamt, sdsq, s, lamdp, phidp, sppsq, dd, sd, sl, fac, scl, sav, spp; - lamdp = xy.x / Q->b; nn = 50; do { @@ -135,10 +134,14 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ lamdp -= TOL; spp = sin(phidp); sppsq = spp * spp; + const double denom = 1. - sppsq * (1. + Q->u); + if( denom == 0.0 ) { + proj_errno_set(P, PJD_ERR_INVALID_X_OR_Y); + return proj_coord_error().lp; + } lamt = atan(((1. - sppsq * P->rone_es) * tan(lamdp) * Q->ca - spp * Q->sa * sqrt((1. + Q->q * dd) * ( - 1. - sppsq) - sppsq * Q->u) / cos(lamdp)) / (1. - sppsq - * (1. + Q->u))); + 1. - sppsq) - sppsq * Q->u) / cos(lamdp)) / denom); sl = lamt >= 0. ? 1. : -1.; scl = cos(lamdp) >= 0. ? 1. : -1; lamt -= M_HALFPI * (1. - scl) * sl; @@ -205,8 +208,8 @@ PJ *PROJECTION(lsat) { Q->c1 /= 15.; Q->c3 /= 45.; - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = lsat_e_inverse; + P->fwd = lsat_e_forward; return P; } diff --git a/src/projections/mbt_fps.cpp b/src/projections/mbt_fps.cpp index beff3314..9ce2aa36 100644 --- a/src/projections/mbt_fps.cpp +++ b/src/projections/mbt_fps.cpp @@ -16,7 +16,7 @@ PROJ_HEAD(mbt_fps, "McBryde-Thomas Flat-Pole Sine (No. 2)") "\n\tCyl, Sph"; #define C_y 1.44492 #define C1_2 0.33333333333333333333333333 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY mbt_fps_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double k, V, t; int i; @@ -37,7 +37,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP mbt_fps_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double t; @@ -51,8 +51,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(mbt_fps) { P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = mbt_fps_s_inverse; + P->fwd = mbt_fps_s_forward; return P; } diff --git a/src/projections/mbtfpp.cpp b/src/projections/mbtfpp.cpp index ebd860ee..a4ab60b9 100644 --- a/src/projections/mbtfpp.cpp +++ b/src/projections/mbtfpp.cpp @@ -15,7 +15,7 @@ PROJ_HEAD(mbtfpp, "McBride-Thomas Flat-Polar Parabolic") "\n\tCyl, Sph"; #define ONEEPS 1.0000001 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY mbtfpp_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; @@ -26,7 +26,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP mbtfpp_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; lp.phi = xy.y / FYC; @@ -58,8 +58,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(mbtfpp) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = mbtfpp_s_inverse; + P->fwd = mbtfpp_s_forward; return P; } diff --git a/src/projections/mbtfpq.cpp b/src/projections/mbtfpq.cpp index ec49f9ce..9a419790 100644 --- a/src/projections/mbtfpq.cpp +++ b/src/projections/mbtfpq.cpp @@ -18,7 +18,7 @@ PROJ_HEAD(mbtfpq, "McBryde-Thomas Flat-Polar Quartic") "\n\tCyl, Sph"; #define RXC 3.20041258076506210122 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY mbtfpq_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double th1, c; int i; @@ -36,7 +36,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP mbtfpq_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double t; @@ -67,8 +67,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(mbtfpq) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = mbtfpq_s_inverse; + P->fwd = mbtfpq_s_forward; return P; } diff --git a/src/projections/merc.cpp b/src/projections/merc.cpp index 5b65de90..10b8bb90 100644 --- a/src/projections/merc.cpp +++ b/src/projections/merc.cpp @@ -3,10 +3,9 @@ #include <float.h> #include <math.h> -#include "proj_internal.h" #include "proj.h" -#include "proj_math.h" #include "proj_internal.h" +#include "proj_math.h" PROJ_HEAD(merc, "Mercator") "\n\tCyl, Sph&Ell\n\tlat_ts="; PROJ_HEAD(webmerc, "Web Mercator / Pseudo Mercator") "\n\tCyl, Ell\n\t"; @@ -20,7 +19,7 @@ static double logtanpfpim1(double x) { /* log(tan(x/2 + M_FORTPI)) */ return log(tan(M_FORTPI + .5 * x)); } -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +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); @@ -32,7 +31,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +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); @@ -44,7 +43,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +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); @@ -55,7 +54,7 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP merc_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; lp.phi = atan(sinh(xy.y / P->k0)); lp.lam = xy.x / P->k0; @@ -76,15 +75,15 @@ PJ *PROJECTION(merc) { if (P->es != 0.0) { /* ellipsoid */ if (is_phits) P->k0 = pj_msfn(sin(phits), cos(phits), P->es); - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = merc_e_inverse; + P->fwd = merc_e_forward; } else { /* sphere */ if (is_phits) P->k0 = cos(phits); - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = merc_s_inverse; + P->fwd = merc_s_forward; } return P; @@ -95,7 +94,7 @@ PJ *PROJECTION(webmerc) { /* Overriding k_0 with fixed parameter */ P->k0 = 1.0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = merc_s_inverse; + P->fwd = merc_s_forward; return P; } diff --git a/src/projections/mill.cpp b/src/projections/mill.cpp index 5d4acd89..e6a97057 100644 --- a/src/projections/mill.cpp +++ b/src/projections/mill.cpp @@ -7,7 +7,7 @@ PROJ_HEAD(mill, "Miller Cylindrical") "\n\tCyl, Sph"; -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY mill_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; @@ -18,7 +18,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP mill_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; (void) P; @@ -31,8 +31,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(mill) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = mill_s_inverse; + P->fwd = mill_s_forward; return P; } diff --git a/src/projections/misrsom.cpp b/src/projections/misrsom.cpp index c53f22a1..09e2d8f3 100644 --- a/src/projections/misrsom.cpp +++ b/src/projections/misrsom.cpp @@ -62,7 +62,7 @@ static void seraz0(double lam, double mult, PJ *P) { } -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY misrsom_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); int l, nn; @@ -123,7 +123,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP misrsom_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); int nn; @@ -151,10 +151,14 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ lamdp -= TOL; spp = sin(phidp); sppsq = spp * spp; + const double denom = 1. - sppsq * (1. + Q->u); + if( denom == 0.0 ) { + proj_errno_set(P, PJD_ERR_NON_CONVERGENT); + return proj_coord_error().lp; + } lamt = atan(((1. - sppsq * P->rone_es) * tan(lamdp) * Q->ca - spp * Q->sa * sqrt((1. + Q->q * dd) * ( - 1. - sppsq) - sppsq * Q->u) / cos(lamdp)) / (1. - sppsq - * (1. + Q->u))); + 1. - sppsq) - sppsq * Q->u) / cos(lamdp)) / denom); sl = lamt >= 0. ? 1. : -1.; scl = cos(lamdp) >= 0. ? 1. : -1; lamt -= M_HALFPI * (1. - scl) * sl; @@ -212,8 +216,8 @@ PJ *PROJECTION(misrsom) { Q->c1 /= 15.; Q->c3 /= 45.; - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = misrsom_e_inverse; + P->fwd = misrsom_e_forward; return P; } diff --git a/src/projections/mod_ster.cpp b/src/projections/mod_ster.cpp index 83390178..8e02ea72 100644 --- a/src/projections/mod_ster.cpp +++ b/src/projections/mod_ster.cpp @@ -22,7 +22,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY mod_ster_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double sinlon, coslon, esphi, chi, schi, cchi, s; @@ -35,7 +35,12 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ pow((1. - esphi) / (1. + esphi), P->e * .5)) - M_HALFPI; schi = sin(chi); cchi = cos(chi); - s = 2. / (1. + Q->schio * schi + Q->cchio * cchi * coslon); + const double denom = 1. + Q->schio * schi + Q->cchio * cchi * coslon; + if( denom == 0 ) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + s = 2. / denom; p.r = s * cchi * sinlon; p.i = s * (Q->cchio * schi - Q->schio * cchi * coslon); p = pj_zpoly1(p, Q->zcoeff, Q->n); @@ -46,7 +51,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP mod_ster_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); int nn; @@ -72,7 +77,6 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ z = 2. * atan(.5 * rh); sinz = sin(z); cosz = cos(z); - lp.lam = P->lam0; if (fabs(rh) <= EPSLN) { /* if we end up here input coordinates were (0,0). * pj_inv() adds P->lam0 to lp.lam, this way we are @@ -115,8 +119,8 @@ static PJ *setup(PJ *P) { /* general initialization */ chio = P->phi0; Q->schio = sin(chio); Q->cchio = cos(chio); - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = mod_ster_e_inverse; + P->fwd = mod_ster_e_forward; return P; } diff --git a/src/projections/moll.cpp b/src/projections/moll.cpp index 03393b01..d511c6e0 100644 --- a/src/projections/moll.cpp +++ b/src/projections/moll.cpp @@ -20,7 +20,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY moll_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double k, V; @@ -43,7 +43,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP moll_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); lp.phi = aasin(P->ctx, xy.y / Q->C_y); @@ -70,8 +70,8 @@ static PJ * setup(PJ *P, double p) { Q->C_y = r / sp; Q->C_p = p2 + sin(p2); - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = moll_s_inverse; + P->fwd = moll_s_forward; return P; } @@ -106,8 +106,8 @@ PJ *PROJECTION(wag5) { Q->C_y = 1.65014; Q->C_p = 3.00896; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = moll_s_inverse; + P->fwd = moll_s_forward; return P; } diff --git a/src/projections/natearth.cpp b/src/projections/natearth.cpp index d8e52c37..ff8aef6a 100644 --- a/src/projections/natearth.cpp +++ b/src/projections/natearth.cpp @@ -42,7 +42,7 @@ PROJ_HEAD(natearth, "Natural Earth") "\n\tPCyl, Sph"; #define MAX_ITER 100 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY natearth_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double phi2, phi4; (void) P; @@ -55,7 +55,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP natearth_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double yc, tol, y2, y4, f, fder; int i; @@ -94,8 +94,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(natearth) { P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = natearth_s_inverse; + P->fwd = natearth_s_forward; return P; } diff --git a/src/projections/natearth2.cpp b/src/projections/natearth2.cpp index 9849a723..95d73c36 100644 --- a/src/projections/natearth2.cpp +++ b/src/projections/natearth2.cpp @@ -34,7 +34,7 @@ PROJ_HEAD(natearth2, "Natural Earth 2") "\n\tPCyl, Sph"; #define MAX_ITER 100 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY natearth2_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double phi2, phi4, phi6; (void) P; @@ -49,7 +49,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP natearth2_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double yc, tol, y2, y4, y6, f, fder; int i; @@ -91,8 +91,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(natearth2) { P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = natearth2_s_inverse; + P->fwd = natearth2_s_forward; return P; } diff --git a/src/projections/nell.cpp b/src/projections/nell.cpp index b6e69dd6..63a0eec1 100644 --- a/src/projections/nell.cpp +++ b/src/projections/nell.cpp @@ -11,7 +11,7 @@ PROJ_HEAD(nell, "Nell") "\n\tPCyl, Sph"; #define LOOP_TOL 1e-7 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY nell_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double k, V; int i; @@ -33,7 +33,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP nell_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; lp.lam = 2. * xy.x / (1. + cos(xy.y)); lp.phi = aasin(P->ctx,0.5 * (xy.y + sin(xy.y))); @@ -45,8 +45,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(nell) { P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = nell_s_inverse; + P->fwd = nell_s_forward; return P; } diff --git a/src/projections/nell_h.cpp b/src/projections/nell_h.cpp index be28b917..63d12391 100644 --- a/src/projections/nell_h.cpp +++ b/src/projections/nell_h.cpp @@ -11,7 +11,7 @@ PROJ_HEAD(nell_h, "Nell-Hammer") "\n\tPCyl, Sph"; #define EPS 1e-7 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY nell_h_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; @@ -22,7 +22,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP nell_h_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double V, c, p; int i; @@ -47,8 +47,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(nell_h) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = nell_h_s_inverse; + P->fwd = nell_h_s_forward; return P; } diff --git a/src/projections/nicol.cpp b/src/projections/nicol.cpp index c4bee261..fb1b93ea 100644 --- a/src/projections/nicol.cpp +++ b/src/projections/nicol.cpp @@ -10,7 +10,7 @@ PROJ_HEAD(nicol, "Nicolosi Globular") "\n\tMisc Sph, no inv"; #define EPS 1e-10 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY nicol_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; (void) P; @@ -49,7 +49,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ *PROJECTION(nicol) { P->es = 0.; - P->fwd = s_forward; + P->fwd = nicol_s_forward; return P; } diff --git a/src/projections/nsper.cpp b/src/projections/nsper.cpp index a0bb5686..d641e1b6 100644 --- a/src/projections/nsper.cpp +++ b/src/projections/nsper.cpp @@ -38,7 +38,7 @@ PROJ_HEAD(tpers, "Tilted perspective") "\n\tAzi, Sph\n\ttilt= azi= h="; # define EPS10 1.e-10 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY nsper_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double coslam, cosphi, sinphi; @@ -93,10 +93,10 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP nsper_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); - double rh, cosz, sinz; + double rh; if (Q->tilt) { double bm, bq, yt; @@ -108,16 +108,18 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ xy.y = bq * Q->cg - bm * Q->sg; } rh = hypot(xy.x, xy.y); - if ((sinz = 1. - rh * rh * Q->pfact) < 0.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - sinz = (Q->p - sqrt(sinz)) / (Q->pn1 / rh + rh / Q->pn1); - cosz = sqrt(1. - sinz * sinz); if (fabs(rh) <= EPS10) { lp.lam = 0.; lp.phi = P->phi0; } else { + double cosz, sinz; + sinz = 1. - rh * rh * Q->pfact; + if (sinz < 0.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + sinz = (Q->p - sqrt(sinz)) / (Q->pn1 / rh + rh / Q->pn1); + cosz = sqrt(1. - sinz * sinz); switch (Q->mode) { case OBLIQ: lp.phi = asin(cosz * Q->sinph0 + xy.y * sinz * Q->cosph0 / rh); @@ -146,8 +148,7 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ static PJ *setup(PJ *P) { struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); - if ((Q->height = pj_param(P->ctx, P->params, "dh").f) <= 0.) - return pj_default_destructor(P, PJD_ERR_H_LESS_THAN_ZERO); + Q->height = pj_param(P->ctx, P->params, "dh").f; if (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; @@ -159,12 +160,14 @@ static PJ *setup(PJ *P) { Q->cosph0 = cos(P->phi0); } Q->pn1 = Q->height / P->a; /* normalize by radius */ + if ( Q->pn1 <= 0 || Q->pn1 > 1e10 ) + return pj_default_destructor (P, PJD_ERR_INVALID_H); Q->p = 1. + Q->pn1; Q->rp = 1. / Q->p; Q->h = 1. / Q->pn1; Q->pfact = (Q->p + 1.) * Q->h; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = nsper_s_inverse; + P->fwd = nsper_s_forward; P->es = 0.; return P; diff --git a/src/projections/nzmg.cpp b/src/projections/nzmg.cpp index 1c2d9fb7..2f1a897e 100644 --- a/src/projections/nzmg.cpp +++ b/src/projections/nzmg.cpp @@ -58,7 +58,7 @@ static const double tpsi[] = { .6399175073, -.1358797613, .063294409, -.02526853 #define Ntphi 8 -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY nzmg_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; COMPLEX p; const double *C; @@ -77,7 +77,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP nzmg_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; int nn, i; COMPLEX p, f, fp, dp; @@ -116,8 +116,8 @@ PJ *PROJECTION(nzmg) { P->x0 = 2510000.; P->y0 = 6023150.; - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = nzmg_e_inverse; + P->fwd = nzmg_e_forward; return P; diff --git a/src/projections/ob_tran.cpp b/src/projections/ob_tran.cpp index 6daae394..f9eaa6f0 100644 --- a/src/projections/ob_tran.cpp +++ b/src/projections/ob_tran.cpp @@ -154,6 +154,11 @@ static ARGS ob_tran_target_params (paralist *params) { if (0!=strncmp (args.argv[i], "o_proj=", 7)) continue; args.argv[i] += 2; + if (strcmp(args.argv[i], "proj=ob_tran") == 0 ) { + pj_dealloc (args.argv); + args.argc = 0; + args.argv = nullptr; + } break; } @@ -164,7 +169,6 @@ static ARGS ob_tran_target_params (paralist *params) { PJ *PROJECTION(ob_tran) { double phip; - char *name; ARGS args; PJ *R; /* projection to rotate */ @@ -176,15 +180,15 @@ PJ *PROJECTION(ob_tran) { P->destructor = destructor; /* get name of projection to be translated */ - if (!(name = pj_param(P->ctx, P->params, "so_proj").s)) + if (pj_param(P->ctx, P->params, "so_proj").s == nullptr) return destructor(P, PJD_ERR_NO_ROTATION_PROJ); - /* avoid endless recursion */ - if( strcmp(name, "ob_tran") == 0 ) - return destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); - /* Create the target projection object to rotate */ args = ob_tran_target_params (P->params); + /* avoid endless recursion */ + 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); diff --git a/src/projections/ocea.cpp b/src/projections/ocea.cpp index 75aa6666..646b8638 100644 --- a/src/projections/ocea.cpp +++ b/src/projections/ocea.cpp @@ -15,13 +15,11 @@ struct pj_opaque { double rtk; double sinphi; double cosphi; - double singam; - double cosgam; }; } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY ocea_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double t; @@ -36,7 +34,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP ocea_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double t, s; @@ -52,7 +50,7 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(ocea) { - double phi_0=0.0, phi_1, phi_2, lam_1, lam_2, lonz, alpha; + 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))); if (nullptr==Q) @@ -61,15 +59,21 @@ PJ *PROJECTION(ocea) { Q->rok = 1. / P->k0; Q->rtk = P->k0; + double lam_p, phi_p; /*If the keyword "alpha" is found in the sentence then use 1point+1azimuth*/ if ( pj_param(P->ctx, P->params, "talpha").i) { /*Define Pole of oblique transformation from 1 point & 1 azimuth*/ - alpha = pj_param(P->ctx, P->params, "ralpha").f; + // ERO: I've added M_PI so that the alpha is the angle from point 1 to point 2 + // from the North in a clockwise direction + // (to be consistent with omerc behaviour) + alpha = M_PI + pj_param(P->ctx, P->params, "ralpha").f; lonz = pj_param(P->ctx, P->params, "rlonc").f; /*Equation 9-8 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ - Q->singam = atan(-cos(alpha)/(-sin(phi_0) * sin(alpha))) + lonz; + // Actually slightliy modified to use atan2(), as it is suggested by + // Snyder for equation 9-1, but this is not mentionned here + lam_p = atan2(-cos(alpha) , -sin(P->phi0) * sin(alpha)) + lonz; /*Equation 9-7 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ - Q->sinphi = asin(cos(phi_0) * sin(alpha)); + phi_p = asin(cos(P->phi0) * sin(alpha)); /*If the keyword "alpha" is NOT found in the sentence then use 2points*/ } else { /*Define Pole of oblique transformation from 2 points*/ @@ -78,25 +82,32 @@ PJ *PROJECTION(ocea) { lam_1 = pj_param(P->ctx, P->params, "rlon_1").f; lam_2 = pj_param(P->ctx, P->params, "rlon_2").f; /*Equation 9-1 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ - Q->singam = atan2(cos(phi_1) * sin(phi_2) * cos(lam_1) - + lam_p = atan2(cos(phi_1) * sin(phi_2) * cos(lam_1) - sin(phi_1) * cos(phi_2) * cos(lam_2), sin(phi_1) * cos(phi_2) * sin(lam_2) - cos(phi_1) * sin(phi_2) * sin(lam_1) ); /* take care of P->lam0 wrap-around when +lam_1=-90*/ if (lam_1 == -M_HALFPI) - Q->singam = -Q->singam; + lam_p = -lam_p; /*Equation 9-2 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ - Q->sinphi = atan(-cos(Q->singam - lam_1) / tan(phi_1)); + double cos_lamp_m_minus_lam_1 = cos(lam_p - lam_1); + double tan_phi_1 = tan(phi_1); + if( tan_phi_1 == 0.0 ) { + // Not sure if we want to support this case, but at least this avoids + // a division by zero, and gives the same result as the below atan() + phi_p = (cos_lamp_m_minus_lam_1 >= 0.0 ) ? -M_HALFPI : M_HALFPI; + } + else { + phi_p = atan(- cos_lamp_m_minus_lam_1 / tan_phi_1); + } } - P->lam0 = Q->singam + M_HALFPI; - Q->cosphi = cos(Q->sinphi); - Q->sinphi = sin(Q->sinphi); - Q->cosgam = cos(Q->singam); - Q->singam = sin(Q->singam); - P->inv = s_inverse; - P->fwd = s_forward; + P->lam0 = lam_p + M_HALFPI; + Q->cosphi = cos(phi_p); + Q->sinphi = sin(phi_p); + P->inv = ocea_s_inverse; + P->fwd = ocea_s_forward; P->es = 0.; return P; diff --git a/src/projections/oea.cpp b/src/projections/oea.cpp index f2fc1053..ac0f643f 100644 --- a/src/projections/oea.cpp +++ b/src/projections/oea.cpp @@ -16,7 +16,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY oea_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double Az, M, N, cp, sp, cl, shz; @@ -35,7 +35,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP oea_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double N, M, xp, yp, z, Az, cz, sz, cAz; @@ -77,8 +77,8 @@ PJ *PROJECTION(oea) { Q->two_r_m = 2. * Q->rm; Q->hm = 0.5 * Q->m; Q->hn = 0.5 * Q->n; - P->fwd = s_forward; - P->inv = s_inverse; + P->fwd = oea_s_forward; + P->inv = oea_s_inverse; P->es = 0.; } diff --git a/src/projections/omerc.cpp b/src/projections/omerc.cpp index e9b7b4a0..954023df 100644 --- a/src/projections/omerc.cpp +++ b/src/projections/omerc.cpp @@ -45,7 +45,7 @@ struct pj_opaque { #define EPS 1.e-10 -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY omerc_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double S, T, U, V, W, temp, u, v; @@ -84,7 +84,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP omerc_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double u, v, Qp, Sp, Tp, Vp, Up; @@ -97,6 +97,10 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ u = xy.y * Q->cosrot + xy.x * Q->sinrot + Q->u_0; } Qp = exp(- Q->BrA * v); + if( Qp == 0 ) { + proj_errno_set(P, PJD_ERR_INVALID_X_OR_Y); + return proj_coord_error().lp; + } Sp = .5 * (Qp - 1. / Qp); Tp = .5 * (Qp + 1. / Qp); Vp = sin(Q->BrA * u); @@ -150,6 +154,8 @@ PJ *PROJECTION(omerc) { phi1 = pj_param(P->ctx, P->params, "rlat_1").f; lam2 = pj_param(P->ctx, P->params, "rlon_2").f; phi2 = pj_param(P->ctx, P->params, "rlat_2").f; + if (fabs(phi1) > M_HALFPI || fabs(phi2) > M_HALFPI) + return pj_default_destructor(P, PJD_ERR_LAT_LARGER_THAN_90); if (fabs(phi1 - phi2) <= TOL || (con = fabs(phi1)) <= TOL || fabs(con - M_HALFPI) <= TOL || @@ -187,6 +193,9 @@ PJ *PROJECTION(omerc) { gamma = alpha_c; } else alpha_c = aasin(P->ctx, D*sin(gamma0 = gamma)); + if( fabs(fabs(P->phi0) - M_HALFPI) <= TOL ) { + return pj_default_destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); + } P->lam0 = lamc - aasin(P->ctx, .5 * (F - 1. / F) * tan(gamma0)) / Q->B; } else { @@ -194,6 +203,10 @@ PJ *PROJECTION(omerc) { L = pow(pj_tsfn(phi2, sin(phi2), P->e), Q->B); F = Q->E / H; p = (L - H) / (L + H); + if( p == 0 ) { + // Not quite, but es is very close to 1... + return pj_default_destructor(P, PJD_ERR_INVALID_ECCENTRICITY); + } J = Q->E * Q->E; J = (J - L * H) / (J + L * H); if ((con = lam1 - lam2) < -M_PI) @@ -202,8 +215,11 @@ PJ *PROJECTION(omerc) { lam2 += M_TWOPI; P->lam0 = adjlon(.5 * (lam1 + lam2) - atan( J * tan(.5 * Q->B * (lam1 - lam2)) / p) / Q->B); - gamma0 = atan(2. * sin(Q->B * adjlon(lam1 - P->lam0)) / - (F - 1. / F)); + const double denom = F - 1. / F; + if( denom == 0 ) { + return pj_default_destructor(P, PJD_ERR_INVALID_ECCENTRICITY); + } + gamma0 = atan(2. * sin(Q->B * adjlon(lam1 - P->lam0)) / denom); gamma = alpha_c = aasin(P->ctx, D * sin(gamma0)); } Q->singam = sin(gamma0); @@ -222,8 +238,8 @@ PJ *PROJECTION(omerc) { F = 0.5 * gamma0; Q->v_pole_n = Q->ArB * log(tan(M_FORTPI - F)); Q->v_pole_s = Q->ArB * log(tan(M_FORTPI + F)); - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = omerc_e_inverse; + P->fwd = omerc_e_forward; return P; } diff --git a/src/projections/ortho.cpp b/src/projections/ortho.cpp index d4300bd5..94764756 100644 --- a/src/projections/ortho.cpp +++ b/src/projections/ortho.cpp @@ -3,7 +3,6 @@ #include "proj.h" #include "proj_internal.h" #include "proj_math.h" -#include "proj_internal.h" PROJ_HEAD(ortho, "Orthographic") "\n\tAzi, Sph"; @@ -33,7 +32,7 @@ static PJ_XY forward_error(PJ *P, PJ_LP lp, PJ_XY xy) { return xy; } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY ortho_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double coslam, cosphi, sinphi; @@ -67,7 +66,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP ortho_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double rh, cosc, sinc; @@ -134,8 +133,8 @@ PJ *PROJECTION(ortho) { Q->cosph0 = cos(P->phi0); } else Q->mode = EQUIT; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = ortho_s_inverse; + P->fwd = ortho_s_forward; P->es = 0.; return P; diff --git a/src/projections/patterson.cpp b/src/projections/patterson.cpp index 7f0ea3a9..16e7b746 100644 --- a/src/projections/patterson.cpp +++ b/src/projections/patterson.cpp @@ -61,7 +61,7 @@ PROJ_HEAD(patterson, "Patterson Cylindrical") "\n\tCyl"; #define MAX_ITER 100 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY patterson_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double phi2; (void) P; @@ -74,7 +74,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP patterson_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double yc, tol, y2, f, fder; int i; @@ -111,8 +111,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(patterson) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = patterson_s_inverse; + P->fwd = patterson_s_forward; return P; } diff --git a/src/projections/poly.cpp b/src/projections/poly.cpp index b4b61b00..08a4aaad 100644 --- a/src/projections/poly.cpp +++ b/src/projections/poly.cpp @@ -23,7 +23,7 @@ struct pj_opaque { #define ITOL 1.e-12 -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY poly_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double ms, sp, cp; @@ -42,7 +42,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY poly_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cot, E; @@ -60,7 +60,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP poly_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -104,7 +104,7 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP poly_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double B, dphi, tp; int i; @@ -159,12 +159,12 @@ PJ *PROJECTION(poly) { if (!(Q->en = pj_enfn(P->es))) return pj_default_destructor (P, ENOMEM); Q->ml0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), Q->en); - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = poly_e_inverse; + P->fwd = poly_e_forward; } else { Q->ml0 = -P->phi0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = poly_s_inverse; + P->fwd = poly_s_forward; } return P; diff --git a/src/projections/putp2.cpp b/src/projections/putp2.cpp index d5b3b9f5..a11e479e 100644 --- a/src/projections/putp2.cpp +++ b/src/projections/putp2.cpp @@ -15,7 +15,7 @@ PROJ_HEAD(putp2, "Putnins P2") "\n\tPCyl, Sph"; #define PI_DIV_3 1.0471975511965977 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY putp2_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double p, c, s, V; int i; @@ -41,7 +41,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP putp2_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double c; @@ -55,8 +55,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(putp2) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = putp2_s_inverse; + P->fwd = putp2_s_forward; return P; } diff --git a/src/projections/putp3.cpp b/src/projections/putp3.cpp index bc4a02e4..c2df20e8 100644 --- a/src/projections/putp3.cpp +++ b/src/projections/putp3.cpp @@ -17,7 +17,7 @@ PROJ_HEAD(putp3p, "Putnins P3'") "\n\tPCyl, Sph"; #define RPISQ 0.1013211836 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY putp3_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; xy.x = C * lp.lam * (1. - static_cast<struct pj_opaque*>(P->opaque)->A * lp.phi * lp.phi); @@ -27,7 +27,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP putp3_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; lp.phi = xy.y / C; @@ -46,8 +46,8 @@ PJ *PROJECTION(putp3) { Q->A = 4. * RPISQ; P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = putp3_s_inverse; + P->fwd = putp3_s_forward; return P; } @@ -61,8 +61,8 @@ PJ *PROJECTION(putp3p) { Q->A = 2. * RPISQ; P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = putp3_s_inverse; + P->fwd = putp3_s_forward; return P; } diff --git a/src/projections/putp4p.cpp b/src/projections/putp4p.cpp index 462dae81..a5728b74 100644 --- a/src/projections/putp4p.cpp +++ b/src/projections/putp4p.cpp @@ -16,7 +16,7 @@ PROJ_HEAD(putp4p, "Putnins P4'") "\n\tPCyl, Sph"; PROJ_HEAD(weren, "Werenskiold I") "\n\tPCyl, Sph"; -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY putp4p_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -29,7 +29,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP putp4p_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -53,8 +53,8 @@ PJ *PROJECTION(putp4p) { Q->C_y = 3.883251825; P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = putp4p_s_inverse; + P->fwd = putp4p_s_forward; return P; } @@ -70,8 +70,8 @@ PJ *PROJECTION(weren) { Q->C_y = 4.442882938; P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = putp4p_s_inverse; + P->fwd = putp4p_s_forward; return P; } diff --git a/src/projections/putp5.cpp b/src/projections/putp5.cpp index 62cb2ea9..1847e7a9 100644 --- a/src/projections/putp5.cpp +++ b/src/projections/putp5.cpp @@ -19,7 +19,7 @@ PROJ_HEAD(putp5p, "Putnins P5'") "\n\tPCyl, Sph"; #define D 1.2158542 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY putp5_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -30,7 +30,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP putp5_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -52,8 +52,8 @@ PJ *PROJECTION(putp5) { Q->B = 1.; P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = putp5_s_inverse; + P->fwd = putp5_s_forward; return P; } @@ -69,8 +69,8 @@ PJ *PROJECTION(putp5p) { Q->B = 0.5; P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = putp5_s_inverse; + P->fwd = putp5_s_forward; return P; } diff --git a/src/projections/putp6.cpp b/src/projections/putp6.cpp index 4bae7ae6..bcf9ad8e 100644 --- a/src/projections/putp6.cpp +++ b/src/projections/putp6.cpp @@ -20,7 +20,7 @@ PROJ_HEAD(putp6p, "Putnins P6'") "\n\tPCyl, Sph"; #define CON_POLE 1.732050807568877 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY putp6_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double p, r, V; @@ -44,7 +44,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP putp6_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double r; @@ -71,8 +71,8 @@ PJ *PROJECTION(putp6) { Q->D = 2.; P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = putp6_s_inverse; + P->fwd = putp6_s_forward; return P; } @@ -91,8 +91,8 @@ PJ *PROJECTION(putp6p) { Q->D = 3.; P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = putp6_s_inverse; + P->fwd = putp6_s_forward; return P; } diff --git a/src/projections/qsc.cpp b/src/projections/qsc.cpp index 409afb38..98e3755e 100644 --- a/src/projections/qsc.cpp +++ b/src/projections/qsc.cpp @@ -119,7 +119,7 @@ static double qsc_shift_lon_origin(double lon, double offset) { } -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY qsc_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double lat, lon; @@ -235,7 +235,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP qsc_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double mu, nu, cosmu, tannu; @@ -382,8 +382,8 @@ PJ *PROJECTION(qsc) { return pj_default_destructor (P, ENOMEM); P->opaque = Q; - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = qsc_e_inverse; + P->fwd = qsc_e_forward; /* Determine the cube face from the center of projection. */ if (P->phi0 >= M_HALFPI - M_FORTPI / 2.0) { Q->face = FACE_TOP; diff --git a/src/projections/robin.cpp b/src/projections/robin.cpp index 8f142aad..c08ac0e2 100644 --- a/src/projections/robin.cpp +++ b/src/projections/robin.cpp @@ -1,13 +1,12 @@ #define PJ_LIB__ -#include "proj_math.h" -#include "proj_internal.h" #include "proj.h" #include "proj_internal.h" +#include "proj_math.h" PROJ_HEAD(robin, "Robinson") "\n\tPCyl, Sph"; #define V(C,z) (C.c0 + z * (C.c1 + z * (C.c2 + z * C.c3))) -#define DV(C,z) (C.c1 + z * (C.c2 + C.c2 + z * 3. * C.c3)) +#define DV(C,z) (C.c1 + 2 * z * C.c2 + z * z * 3. * C.c3) /* note: following terms based upon 5 deg. intervals in degrees. @@ -74,11 +73,11 @@ static const struct COEFS Y[] = { #define RC1 0.08726646259971647884 #define NODES 18 #define ONEEPS 1.000001 -#define EPS 1e-8 +#define EPS 1e-10 /* Not sure at all of the appropriate number for MAX_ITER... */ #define MAX_ITER 100 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY robin_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; long i; double dphi; @@ -90,7 +89,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); return xy; } - if (i >= NODES) i = NODES - 1; + if (i >= NODES) i = NODES; dphi = RAD_TO_DEG * (dphi - RC1 * i); xy.x = V(X[i], dphi) * FXC * lp.lam; xy.y = V(Y[i], dphi) * FYC; @@ -100,7 +99,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP robin_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; long i; double t, t1; @@ -133,10 +132,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ T = Y[i]; /* first guess, linear interp */ t = 5. * (lp.phi - T.c0)/(Y[i+1].c0 - T.c0); - /* make into root */ - T.c0 = (float)(T.c0 - lp.phi); for (iters = MAX_ITER; iters ; --iters) { /* Newton-Raphson */ - t -= t1 = V(T,t) / DV(T,t); + t -= t1 = (V(T,t) - lp.phi) / DV(T,t); if (fabs(t1) < EPS) break; } @@ -152,8 +149,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(robin) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = robin_s_inverse; + P->fwd = robin_s_forward; return P; } diff --git a/src/projections/rouss.cpp b/src/projections/rouss.cpp index f58277b8..f5a8f12f 100644 --- a/src/projections/rouss.cpp +++ b/src/projections/rouss.cpp @@ -44,7 +44,7 @@ struct pj_opaque { PROJ_HEAD(rouss, "Roussilhe Stereographic") "\n\tAzi, Ell"; -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY rouss_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double s, al, cp, sp, al2, s2; @@ -65,7 +65,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP rouss_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double s, al, x = xy.x / P->k0, y = xy.y / P->k0, x2, y2;; @@ -150,8 +150,8 @@ PJ *PROJECTION(rouss) { Q->D10 = R_R0_4 * t * (29. + t2 * (86. + t2 * 48.))/(96. * N0); Q->D11 = R_R0_4 * t * (37. + t2 * 44.)/(96. * N0); - P->fwd = e_forward; - P->inv = e_inverse; + P->fwd = rouss_e_forward; + P->inv = rouss_e_inverse; P->destructor = destructor; return P; diff --git a/src/projections/rpoly.cpp b/src/projections/rpoly.cpp index 6e883ab2..58decf66 100644 --- a/src/projections/rpoly.cpp +++ b/src/projections/rpoly.cpp @@ -20,7 +20,7 @@ PROJ_HEAD(rpoly, "Rectangular Polyconic") #define EPS 1e-9 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY rpoly_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double fa; @@ -53,7 +53,7 @@ PJ *PROJECTION(rpoly) { Q->fxa = 0.5 / Q->fxb; } P->es = 0.; - P->fwd = s_forward; + P->fwd = rpoly_s_forward; return P; } diff --git a/src/projections/sch.cpp b/src/projections/sch.cpp index f4c66688..e302c1da 100644 --- a/src/projections/sch.cpp +++ b/src/projections/sch.cpp @@ -55,7 +55,7 @@ struct pj_opaque { PROJ_HEAD(sch, "Spherical Cross-track Height") "\n\tMisc\n\tplat_0= plon_0= phdg_0= [h_0=]"; -static PJ_LPZ inverse3d(PJ_XYZ xyz, PJ *P) { +static PJ_LPZ sch_inverse3d(PJ_XYZ xyz, PJ *P) { PJ_LPZ lpz = {0.0, 0.0, 0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double temp[3]; @@ -93,7 +93,7 @@ static PJ_LPZ inverse3d(PJ_XYZ xyz, PJ *P) { return lpz; } -static PJ_XYZ forward3d(PJ_LPZ lpz, PJ *P) { +static PJ_XYZ sch_forward3d(PJ_LPZ lpz, PJ *P) { PJ_XYZ xyz = {0.0, 0.0, 0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double temp[3]; @@ -187,8 +187,8 @@ static PJ *setup(PJ *P) { /* general initialization */ Q->xyzoff[1] = pxyz[1] - (Q->rcurv) * clt * slo; Q->xyzoff[2] = pxyz[2] - (Q->rcurv) * slt; - P->fwd3d = forward3d; - P->inv3d = inverse3d; + P->fwd3d = sch_forward3d; + P->inv3d = sch_inverse3d; return P; } @@ -215,7 +215,7 @@ PJ *PROJECTION(sch) { return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); } - /* Check if peg latitude is defined */ + /* Check if peg heading is defined */ if (pj_param(P->ctx, P->params, "tphdg_0").i) Q->phdg = pj_param(P->ctx, P->params, "rphdg_0").f; else { diff --git a/src/projections/sconics.cpp b/src/projections/sconics.cpp index 7bdd2603..1a16fe24 100644 --- a/src/projections/sconics.cpp +++ b/src/projections/sconics.cpp @@ -62,7 +62,7 @@ static int phi12(PJ *P, double *del) { } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY sconics_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0, 0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double rho; @@ -85,7 +85,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, (and ellipsoidal?) inverse */ +static PJ_LP sconics_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, (and ellipsoidal?) inverse */ PJ_LP lp = {0.0, 0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double rho; @@ -177,8 +177,8 @@ static PJ *setup(PJ *P, enum Type type) { break; } - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = sconics_s_inverse; + P->fwd = sconics_s_forward; P->es = 0; return (P); } diff --git a/src/projections/somerc.cpp b/src/projections/somerc.cpp index ead9090f..be1f660d 100644 --- a/src/projections/somerc.cpp +++ b/src/projections/somerc.cpp @@ -18,7 +18,7 @@ struct pj_opaque { #define NITER 6 -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY somerc_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0, 0.0}; double phip, lamp, phipp, lampp, sp, cp; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); @@ -37,7 +37,7 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP somerc_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double phip, lamp, phipp, lampp, cp, esp, con, delp; @@ -88,7 +88,7 @@ PJ *PROJECTION(somerc) { log (tan (M_FORTPI + 0.5 * P->phi0)) - Q->hlf_e * log ((1. + sp) / (1. - sp))); Q->kR = P->k0 * sqrt(P->one_es) / (1. - sp * sp); - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = somerc_e_inverse; + P->fwd = somerc_e_forward; return P; } diff --git a/src/projections/stere.cpp b/src/projections/stere.cpp index 9b24a596..683d484c 100644 --- a/src/projections/stere.cpp +++ b/src/projections/stere.cpp @@ -41,7 +41,7 @@ static double ssfn_ (double phit, double sinphi, double eccen) { } -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY stere_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double coslam, sinlam, sinX = 0.0, cosX = 0.0, X, A = 0.0, sinphi; @@ -55,11 +55,18 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ } switch (Q->mode) { - case OBLIQ: - A = Q->akm1 / (Q->cosX1 * (1. + Q->sinX1 * sinX + - Q->cosX1 * cosX * coslam)); + case OBLIQ: { + const double denom = Q->cosX1 * (1. + Q->sinX1 * sinX + + Q->cosX1 * cosX * coslam); + if( denom == 0 ) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return proj_coord_error().xy; + } + A = Q->akm1 / denom; xy.y = A * (Q->cosX1 * sinX - Q->sinX1 * cosX * coslam); - goto xmul; /* but why not just xy.x = A * cosX; break; ? */ + xy.x = A * cosX; + break; + } case EQUIT: /* avoid zero division */ @@ -69,7 +76,6 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ A = Q->akm1 / (1. + cosX * coslam); xy.y = A * sinX; } -xmul: xy.x = A * cosX; break; @@ -89,7 +95,7 @@ xmul: } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY stere_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double sinphi, cosphi, coslam, sinlam; @@ -131,7 +137,7 @@ oblcon: } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP stere_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cosphi, sinphi, tp=0.0, phi_l=0.0, rho, halfe=0.0, halfpi=0.0; @@ -165,7 +171,7 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ break; } - for (i = NITER; i--; phi_l = lp.phi) { + for (i = NITER; i--; ) { sinphi = P->e * sin(phi_l); lp.phi = 2. * atan (tp * pow ((1.+sinphi)/(1.-sinphi), halfe)) - halfpi; if (fabs (phi_l - lp.phi) < CONV) { @@ -174,6 +180,7 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ lp.lam = (xy.x == 0. && xy.y == 0.) ? 0. : atan2 (xy.x, xy.y); return lp; } + phi_l = lp.phi; } proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); @@ -181,7 +188,7 @@ static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP stere_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double c, rh, sinc, cosc; @@ -258,8 +265,8 @@ static PJ *setup(PJ *P) { /* general initialization */ Q->cosX1 = cos (X); break; } - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = stere_e_inverse; + P->fwd = stere_e_forward; } else { switch (Q->mode) { case OBLIQ: @@ -277,8 +284,8 @@ static PJ *setup(PJ *P) { /* general initialization */ break; } - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = stere_s_inverse; + P->fwd = stere_s_forward; } return P; } diff --git a/src/projections/sterea.cpp b/src/projections/sterea.cpp index b6ebc7b4..ca3bfd06 100644 --- a/src/projections/sterea.cpp +++ b/src/projections/sterea.cpp @@ -44,7 +44,7 @@ PROJ_HEAD(sterea, "Oblique Stereographic Alternative") "\n\tAzimuthal, Sph&Ell"; -static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ +static PJ_XY sterea_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cosc, sinc, cosl, k; @@ -53,14 +53,19 @@ static PJ_XY e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ sinc = sin(lp.phi); cosc = cos(lp.phi); cosl = cos(lp.lam); - k = P->k0 * Q->R2 / (1. + Q->sinc0 * sinc + Q->cosc0 * cosc * cosl); + const double denom = 1. + Q->sinc0 * sinc + Q->cosc0 * cosc * cosl; + if( denom == 0.0 ) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return proj_coord_error().xy; + } + k = P->k0 * Q->R2 / denom; xy.x = k * cosc * sin(lp.lam); xy.y = k * (Q->cosc0 * sinc - Q->sinc0 * cosc * cosl); return xy; } -static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ +static PJ_LP sterea_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double rho, c, sinc, cosc; @@ -109,8 +114,8 @@ PJ *PROJECTION(sterea) { Q->cosc0 = cos (Q->phic0); Q->R2 = 2. * R; - P->inv = e_inverse; - P->fwd = e_forward; + P->inv = sterea_e_inverse; + P->fwd = sterea_e_forward; P->destructor = destructor; return P; diff --git a/src/projections/sts.cpp b/src/projections/sts.cpp index 27dc3eb8..4d682a53 100644 --- a/src/projections/sts.cpp +++ b/src/projections/sts.cpp @@ -20,7 +20,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY sts_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double c; @@ -40,7 +40,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP sts_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double c; @@ -59,8 +59,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ static PJ *setup(PJ *P, double p, double q, int mode) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = sts_s_inverse; + P->fwd = sts_s_forward; static_cast<struct pj_opaque*>(P->opaque)->C_x = q / p; static_cast<struct pj_opaque*>(P->opaque)->C_y = p; static_cast<struct pj_opaque*>(P->opaque)->C_p = 1/ q; diff --git a/src/projections/tcc.cpp b/src/projections/tcc.cpp index cfac9974..3dd47940 100644 --- a/src/projections/tcc.cpp +++ b/src/projections/tcc.cpp @@ -10,7 +10,7 @@ PROJ_HEAD(tcc, "Transverse Central Cylindrical") "\n\tCyl, Sph, no inv"; #define EPS10 1.e-10 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY tcc_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0, 0.0}; double b, bt; @@ -27,7 +27,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ *PROJECTION(tcc) { P->es = 0.; - P->fwd = s_forward; + P->fwd = tcc_s_forward; P->inv = nullptr; return P; diff --git a/src/projections/tcea.cpp b/src/projections/tcea.cpp index d780718d..a3c771ff 100644 --- a/src/projections/tcea.cpp +++ b/src/projections/tcea.cpp @@ -8,7 +8,7 @@ PROJ_HEAD(tcea, "Transverse Cylindrical Equal Area") "\n\tCyl, Sph"; -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY tcea_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; xy.x = cos (lp.phi) * sin (lp.lam) / P->k0; xy.y = P->k0 * (atan2 (tan (lp.phi), cos (lp.lam)) - P->phi0); @@ -16,7 +16,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP tcea_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0, 0.0}; double t; @@ -30,8 +30,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(tcea) { - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = tcea_s_inverse; + P->fwd = tcea_s_forward; P->es = 0.; return P; } diff --git a/src/projections/times.cpp b/src/projections/times.cpp index 4a0d0f59..21c6c19a 100644 --- a/src/projections/times.cpp +++ b/src/projections/times.cpp @@ -38,7 +38,7 @@ PROJ_HEAD(times, "Times") "\n\tCyl, Sph"; -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY times_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ double T, S, S2; PJ_XY xy = {0.0,0.0}; (void) P; @@ -54,7 +54,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP times_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ double T, S, S2; PJ_LP lp = {0.0,0.0}; (void) P; @@ -73,8 +73,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(times) { P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = times_s_inverse; + P->fwd = times_s_forward; return P; } diff --git a/src/projections/tmerc.cpp b/src/projections/tmerc.cpp index c91c5174..bb56f8ae 100644 --- a/src/projections/tmerc.cpp +++ b/src/projections/tmerc.cpp @@ -188,6 +188,10 @@ static PJ_LP approx_s_inv (PJ_XY xy, PJ *P) { double h, g; h = exp(xy.x / static_cast<struct pj_opaque_approx*>(P->opaque)->esp); + if( h == 0 ) { + proj_errno_set(P, PJD_ERR_INVALID_X_OR_Y); + return proj_coord_error().lp; + } g = .5 * (h - 1. / h); h = cos (P->phi0 + xy.y / static_cast<struct pj_opaque_approx*>(P->opaque)->esp); lp.phi = asin(sqrt((1. - h * h) / (1. + g * g))); diff --git a/src/projections/tobmerc.cpp b/src/projections/tobmerc.cpp index 95960097..7215f0db 100644 --- a/src/projections/tobmerc.cpp +++ b/src/projections/tobmerc.cpp @@ -3,10 +3,9 @@ #include <float.h> #include <math.h> -#include "proj_internal.h" #include "proj.h" -#include "proj_math.h" #include "proj_internal.h" +#include "proj_math.h" PROJ_HEAD(tobmerc, "Tobler-Mercator") "\n\tCyl, Sph"; @@ -19,7 +18,7 @@ static double logtanpfpim1(double x) { /* log(tan(x/2 + M_FORTPI)) */ return log(tan(M_FORTPI + .5 * x)); } -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY tobmerc_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0, 0.0}; double cosphi; @@ -34,7 +33,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ return xy; } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP tobmerc_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0, 0.0}; double cosphi; @@ -45,7 +44,7 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ } PJ *PROJECTION(tobmerc) { - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = tobmerc_s_inverse; + P->fwd = tobmerc_s_forward; return P; } diff --git a/src/projections/tpeqd.cpp b/src/projections/tpeqd.cpp index 20921de4..b306968c 100644 --- a/src/projections/tpeqd.cpp +++ b/src/projections/tpeqd.cpp @@ -16,7 +16,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY tpeqd_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0, 0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double t, z1, z2, dl1, dl2, sp, cp; @@ -37,7 +37,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP tpeqd_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cz1, cz2, s, d, cp, sp; @@ -87,6 +87,10 @@ PJ *PROJECTION(tpeqd) { Q->sc = Q->sp1 * Q->cp2; Q->ccs = Q->cp1 * Q->cp2 * sin(Q->dlam2); Q->z02 = aacos(P->ctx, Q->sp1 * Q->sp2 + Q->cp1 * Q->cp2 * cos (Q->dlam2)); + if( Q->z02 == 0.0 ) { + // Actually happens when both lat_1 = lat_2 and |lat_1| = 90 + return pj_default_destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); + } Q->hz0 = .5 * Q->z02; A12 = atan2(Q->cp2 * sin (Q->dlam2), Q->cp1 * Q->sp2 - Q->sp1 * Q->cp2 * cos (Q->dlam2)); @@ -100,8 +104,8 @@ PJ *PROJECTION(tpeqd) { Q->r2z0 = 0.5 / Q->z02; Q->z02 *= Q->z02; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = tpeqd_s_inverse; + P->fwd = tpeqd_s_forward; P->es = 0.; return P; diff --git a/src/projections/urm5.cpp b/src/projections/urm5.cpp index a93293c0..499644d2 100644 --- a/src/projections/urm5.cpp +++ b/src/projections/urm5.cpp @@ -15,7 +15,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY urm5_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0, 0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double t; @@ -45,12 +45,16 @@ PJ *PROJECTION(urm5) { Q->q3 = pj_param(P->ctx, P->params, "dq").f / 3.; alpha = pj_param(P->ctx, P->params, "ralpha").f; t = Q->n * sin (alpha); - Q->m = cos (alpha) / sqrt (1. - t * t); + const double denom = sqrt (1. - t * t); + if( denom == 0 ) { + return pj_default_destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); + } + Q->m = cos (alpha) / denom; Q->rmn = 1. / (Q->m * Q->n); P->es = 0.; P->inv = nullptr; - P->fwd = s_forward; + P->fwd = urm5_s_forward; return P; } diff --git a/src/projections/urmfps.cpp b/src/projections/urmfps.cpp index 3a51798b..3f9fdf23 100644 --- a/src/projections/urmfps.cpp +++ b/src/projections/urmfps.cpp @@ -19,7 +19,7 @@ struct pj_opaque { #define Cy 1.139753528477 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY urmfps_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0, 0.0}; lp.phi = aasin (P->ctx,static_cast<struct pj_opaque*>(P->opaque)->n * sin (lp.phi)); xy.x = C_x * lp.lam * cos (lp.phi); @@ -28,7 +28,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP urmfps_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0, 0.0}; xy.y /= static_cast<struct pj_opaque*>(P->opaque)->C_y; lp.phi = aasin(P->ctx, sin (xy.y) / static_cast<struct pj_opaque*>(P->opaque)->n); @@ -40,8 +40,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ static PJ *setup(PJ *P) { static_cast<struct pj_opaque*>(P->opaque)->C_y = Cy / static_cast<struct pj_opaque*>(P->opaque)->n; P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = urmfps_s_inverse; + P->fwd = urmfps_s_forward; return P; } diff --git a/src/projections/vandg.cpp b/src/projections/vandg.cpp index 89620356..7d485aff 100644 --- a/src/projections/vandg.cpp +++ b/src/projections/vandg.cpp @@ -13,7 +13,7 @@ PROJ_HEAD(vandg, "van der Grinten (I)") "\n\tMisc Sph"; # define HPISQ 4.93480220054467930934 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY vandg_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double al, al2, g, g2, p2; @@ -58,7 +58,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP vandg_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double t, c0, c1, c2, c3, al, r2, r, m, d, ay, x2, y2; @@ -80,7 +80,14 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ al = c1 / c3 - THIRD * c2 * c2; m = 2. * sqrt(-THIRD * al); d = C2_27 * c2 * c2 * c2 + (c0 * c0 - THIRD * c2 * c1) / c3; - if (((t = fabs(d = 3. * d / (al * m))) - TOL) <= 1.) { + const double al_mul_m = al * m; + if( al_mul_m == 0 ) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return proj_coord_error().lp; + } + d = 3. * d /al_mul_m; + t = fabs(d); + if ((t - TOL) <= 1.) { d = t > 1. ? (d > 0. ? 0. : M_PI) : acos(d); lp.phi = M_PI * (m * cos(d * THIRD + PI4_3) - THIRD * c2); if (xy.y < 0.) lp.phi = -lp.phi; @@ -98,8 +105,8 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(vandg) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = vandg_s_inverse; + P->fwd = vandg_s_forward; return P; } diff --git a/src/projections/vandg2.cpp b/src/projections/vandg2.cpp index de63b085..05314833 100644 --- a/src/projections/vandg2.cpp +++ b/src/projections/vandg2.cpp @@ -18,7 +18,7 @@ PROJ_HEAD(vandg3, "van der Grinten III") "\n\tMisc Sph, no inv"; #define TOL 1e-10 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY vandg2_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double x1, at, bt, ct; @@ -58,7 +58,7 @@ PJ *PROJECTION(vandg2) { P->opaque = Q; Q->vdg3 = 0; - P->fwd = s_forward; + P->fwd = vandg2_s_forward; return P; } @@ -71,7 +71,7 @@ PJ *PROJECTION(vandg3) { Q->vdg3 = 1; P->es = 0.; - P->fwd = s_forward; + P->fwd = vandg2_s_forward; return P; } diff --git a/src/projections/vandg4.cpp b/src/projections/vandg4.cpp index 8511431d..a5cfd8e6 100644 --- a/src/projections/vandg4.cpp +++ b/src/projections/vandg4.cpp @@ -10,7 +10,7 @@ PROJ_HEAD(vandg4, "van der Grinten IV") "\n\tMisc Sph, no inv"; #define TOL 1e-10 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY vandg4_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; double x1, t, bt, ct, ft, bt2, ct2, dt, dt2; (void) P; @@ -50,7 +50,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ *PROJECTION(vandg4) { P->es = 0.; - P->fwd = s_forward; + P->fwd = vandg4_s_forward; return P; } diff --git a/src/projections/wag2.cpp b/src/projections/wag2.cpp index e04cc648..4e7c28ac 100644 --- a/src/projections/wag2.cpp +++ b/src/projections/wag2.cpp @@ -13,7 +13,7 @@ PROJ_HEAD(wag2, "Wagner II") "\n\tPCyl, Sph"; #define C_p2 0.88550 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY wag2_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; lp.phi = aasin (P->ctx,C_p1 * sin (C_p2 * lp.phi)); xy.x = C_x * lp.lam * cos (lp.phi); @@ -22,7 +22,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP wag2_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; lp.phi = xy.y / C_y; lp.lam = xy.x / (C_x * cos(lp.phi)); @@ -33,7 +33,7 @@ static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(wag2) { P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = wag2_s_inverse; + P->fwd = wag2_s_forward; return P; } diff --git a/src/projections/wag3.cpp b/src/projections/wag3.cpp index ed695ffd..33313cdb 100644 --- a/src/projections/wag3.cpp +++ b/src/projections/wag3.cpp @@ -17,7 +17,7 @@ struct pj_opaque { } // anonymous namespace -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY wag3_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; xy.x = static_cast<struct pj_opaque*>(P->opaque)->C_x * lp.lam * cos(TWOTHIRD * lp.phi); xy.y = lp.phi; @@ -25,7 +25,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP wag3_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; lp.phi = xy.y; lp.lam = xy.x / (static_cast<struct pj_opaque*>(P->opaque)->C_x * cos(TWOTHIRD * lp.phi)); @@ -44,8 +44,8 @@ PJ *PROJECTION(wag3) { ts = pj_param (P->ctx, P->params, "rlat_ts").f; static_cast<struct pj_opaque*>(P->opaque)->C_x = cos (ts) / cos (2.*ts/3.); P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = wag3_s_inverse; + P->fwd = wag3_s_forward; return P; } diff --git a/src/projections/wag7.cpp b/src/projections/wag7.cpp index 45b70ee2..3afb5a03 100644 --- a/src/projections/wag7.cpp +++ b/src/projections/wag7.cpp @@ -9,7 +9,7 @@ PROJ_HEAD(wag7, "Wagner VII") "\n\tMisc Sph, no inv"; -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY wag7_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0, 0.0}; double theta, ct, D; @@ -24,7 +24,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ *PROJECTION(wag7) { - P->fwd = s_forward; + P->fwd = wag7_s_forward; P->inv = nullptr; P->es = 0.; return P; diff --git a/src/projections/wink1.cpp b/src/projections/wink1.cpp index 75abbffc..d097978f 100644 --- a/src/projections/wink1.cpp +++ b/src/projections/wink1.cpp @@ -16,7 +16,7 @@ struct pj_opaque { -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY wink1_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; xy.x = .5 * lp.lam * (static_cast<struct pj_opaque*>(P->opaque)->cosphi1 + cos(lp.phi)); xy.y = lp.phi; @@ -24,7 +24,7 @@ static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ } -static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ +static PJ_LP wink1_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; lp.phi = xy.y; lp.lam = 2. * xy.x / (static_cast<struct pj_opaque*>(P->opaque)->cosphi1 + cos(lp.phi)); @@ -40,8 +40,8 @@ PJ *PROJECTION(wink1) { static_cast<struct pj_opaque*>(P->opaque)->cosphi1 = cos (pj_param(P->ctx, P->params, "rlat_ts").f); P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; + P->inv = wink1_s_inverse; + P->fwd = wink1_s_forward; return P; } diff --git a/src/projections/wink2.cpp b/src/projections/wink2.cpp index 6957bde1..4aaf1972 100644 --- a/src/projections/wink2.cpp +++ b/src/projections/wink2.cpp @@ -18,7 +18,7 @@ struct pj_opaque { #define LOOP_TOL 1e-7 -static PJ_XY s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ +static PJ_XY wink2_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0, 0.0}; double k, V; int i; @@ -51,7 +51,7 @@ PJ *PROJECTION(wink2) { static_cast<struct pj_opaque*>(P->opaque)->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f); P->es = 0.; P->inv = nullptr; - P->fwd = s_forward; + P->fwd = wink2_s_forward; return P; } diff --git a/src/release.cpp b/src/release.cpp index ddc768c6..822ea4a9 100644 --- a/src/release.cpp +++ b/src/release.cpp @@ -11,7 +11,7 @@ char const pj_release[] = STR(PROJ_VERSION_MAJOR)"." STR(PROJ_VERSION_MINOR)"." STR(PROJ_VERSION_PATCH)", " - "March 1st, 2019"; + "May 15th, 2019"; const char *pj_get_release() { return pj_release; diff --git a/src/strerrno.cpp b/src/strerrno.cpp index 01097a42..9bf5f45a 100644 --- a/src/strerrno.cpp +++ b/src/strerrno.cpp @@ -5,6 +5,7 @@ #include <string.h> #include "proj.h" +#include "proj_config.h" #include "proj_internal.h" static const char * const @@ -14,7 +15,7 @@ pj_err_list[] = { "no colon in init= string", /* -3 */ "projection not named", /* -4 */ "unknown projection id", /* -5 */ - "effective eccentricity = 1.", /* -6 */ + "effective eccentricity < 0 or >= 1.", /* -6 */ "unknown unit conversion id", /* -7 */ "invalid boolean param argument", /* -8 */ "unknown elliptical parameter name", /* -9 */ @@ -30,7 +31,7 @@ pj_err_list[] = { "acos/asin: |arg| >1.+1e-14", /* -19 */ "tolerance condition error", /* -20 */ "conic lat_1 = -lat_2", /* -21 */ - "lat_1 >= 90", /* -22 */ + "lat_0, lat_1 or lat_2 >= 90", /* -22 */ "lat_1 = 0", /* -23 */ "lat_ts >= 90", /* -24 */ "no distance between control points", /* -25 */ @@ -38,10 +39,10 @@ pj_err_list[] = { "W <= 0 or M <= 0", /* -27 */ "lsat not in 1-5 range", /* -28 */ "path not in range", /* -29 */ - "h <= 0", /* -30 */ + "h <= 0 or h > 1e10 * a", /* -30 */ "k <= 0", /* -31 */ - "lat_0 = 0 or 90 or alpha = 90", /* -32 */ - "lat_1=lat_2 or lat_1=0 or lat_2=90", /* -33 */ + "lat_1=lat_2 or lat_1=0 or lat_2=90", /* -32 */ + "lat_0 = 0 or 90 or alpha = 90", /* -33 */ "elliptical usage required", /* -34 */ "invalid UTM zone number", /* -35 */ "", /* no longer used */ /* -36 */ @@ -69,6 +70,7 @@ pj_err_list[] = { "argument not numerical or out of range", /* -58 */ "inconsistent unit type between input and output", /* -59 */ "arguments are mutually exclusive", /* -60 */ + "generic error of unknown origin", /* -61 */ /* When adding error messages, remember to update ID defines in projects.h, and transient_error array in pj_transform */ diff --git a/src/strtod.cpp b/src/strtod.cpp index 7ab271c5..d45e62db 100644 --- a/src/strtod.cpp +++ b/src/strtod.cpp @@ -33,13 +33,8 @@ #include <string.h> #include "proj.h" -#include "proj_internal.h" - -/* Windows nmake build doesn't have a proj_config.h, but HAVE_LOCALECONV */ -/* is defined in the compilation line */ -#ifndef HAVE_LOCALECONV #include "proj_config.h" -#endif +#include "proj_internal.h" #define PJ_STRTOD_WORK_BUFFER_SIZE 64 diff --git a/src/transformations/affine.cpp b/src/transformations/affine.cpp index bda54f1e..28f73b9a 100644 --- a/src/transformations/affine.cpp +++ b/src/transformations/affine.cpp @@ -25,7 +25,6 @@ #include <errno.h> #include <math.h> -#include "proj_internal.h" #include "proj.h" #include "proj_internal.h" diff --git a/src/transformations/deformation.cpp b/src/transformations/deformation.cpp index c28e1489..5bb86909 100644 --- a/src/transformations/deformation.cpp +++ b/src/transformations/deformation.cpp @@ -56,7 +56,6 @@ grid-values in units of mm/year in ENU-space. #include "proj.h" #include "proj_internal.h" #include "proj_math.h" -#include "proj_internal.h" PROJ_HEAD(deformation, "Kinematic grid shift"); @@ -92,7 +91,7 @@ static PJ_XYZ get_grid_shift(PJ* P, PJ_XYZ cartesian) { /* look up correction values in grids */ shift.lp = proj_hgrid_value(P, geodetic.lp); - shift.enu.u = proj_vgrid_value(P, geodetic.lp); + shift.enu.u = proj_vgrid_value(P, geodetic.lp, 1.0); if (proj_errno(P) == PJD_ERR_GRID_AREA) proj_log_debug(P, "deformation: coordinate (%.3f, %.3f) outside deformation model", diff --git a/src/transformations/helmert.cpp b/src/transformations/helmert.cpp index 034f76f4..63785ea5 100644 --- a/src/transformations/helmert.cpp +++ b/src/transformations/helmert.cpp @@ -53,7 +53,6 @@ Last update: 2018-10-26 #include <math.h> #include "proj_internal.h" -#include "proj_internal.h" #include "geocent.h" PROJ_HEAD(helmert, "3(6)-, 4(8)- and 7(14)-parameter Helmert shift"); @@ -567,14 +566,14 @@ PJ *TRANSFORMATION(helmert, 0) { if (pj_param_exists (P->params, "theta")) { P->left = PJ_IO_UNITS_PROJECTED; P->right = PJ_IO_UNITS_PROJECTED; + P->fwd = helmert_forward; + P->inv = helmert_reverse; } P->fwd4d = helmert_forward_4d; P->inv4d = helmert_reverse_4d; P->fwd3d = helmert_forward_3d; P->inv3d = helmert_reverse_3d; - P->fwd = helmert_forward; - P->inv = helmert_reverse; Q = (struct pj_opaque_helmert *)P->opaque; diff --git a/src/transformations/hgridshift.cpp b/src/transformations/hgridshift.cpp index 2e2294cb..90633939 100644 --- a/src/transformations/hgridshift.cpp +++ b/src/transformations/hgridshift.cpp @@ -6,7 +6,6 @@ #include <time.h> #include "proj_internal.h" -#include "proj_internal.h" PROJ_HEAD(hgridshift, "Horizontal grid shift"); diff --git a/src/transformations/horner.cpp b/src/transformations/horner.cpp index f5d749c4..a6638773 100644 --- a/src/transformations/horner.cpp +++ b/src/transformations/horner.cpp @@ -85,7 +85,6 @@ #include "proj.h" #include "proj_internal.h" -#include "proj_internal.h" PROJ_HEAD(horner, "Horner polynomial evaluation"); diff --git a/src/transformations/molodensky.cpp b/src/transformations/molodensky.cpp index c389fd32..7d17f64c 100644 --- a/src/transformations/molodensky.cpp +++ b/src/transformations/molodensky.cpp @@ -49,7 +49,6 @@ #include "proj.h" #include "proj_internal.h" -#include "proj_internal.h" PROJ_HEAD(molodensky, "Molodensky transform"); @@ -140,16 +139,26 @@ static PJ_LPZ calc_standard_params(PJ_LPZ lpz, PJ *P) { /* ellipsoid radii of curvature */ double rho = RM(a, P->es, lpz.phi); - double nu = RN(a, P->e2s, lpz.phi); + double nu = RN(a, P->es, lpz.phi); /* delta phi */ dphi = (-dx*sphi*clam) - (dy*sphi*slam) + (dz*cphi) + ((nu * P->es * sphi * cphi * da) / a) + (sphi*cphi * ( rho/(1-f) + nu*(1-f))*df); - dphi /= (rho + lpz.z); + const double dphi_denom = rho + lpz.z; + if( dphi_denom == 0.0 ) { + lpz.lam = HUGE_VAL; + return lpz; + } + dphi /= dphi_denom; /* delta lambda */ - dlam = (-dx*slam + dy*clam) / ((nu+lpz.z)*cphi); + const double dlam_denom = (nu+lpz.z)*cphi; + if( dlam_denom == 0.0 ) { + lpz.lam = HUGE_VAL; + return lpz; + } + dlam = (-dx*slam + dy*clam) / dlam_denom; /* delta h */ dh = dx*cphi*clam + dy*cphi*slam + dz*sphi - (a/nu)*da + nu*(1-f)*sphi*sphi*df; @@ -183,7 +192,12 @@ static PJ_LPZ calc_abridged_params(PJ_LPZ lpz, PJ *P) { /* delta lambda */ dlam = -dx*slam + dy*clam; - dlam /= RN(P->a, P->e2s, lpz.phi)*cphi; + const double dlam_denom = RN(P->a, P->es, lpz.phi)*cphi; + if( dlam_denom == 0.0 ) { + lpz.lam = HUGE_VAL; + return lpz; + } + dlam /= dlam_denom; /* delta h */ dh = dx*cphi*clam + dy*cphi*slam + dz*sphi - da + adffda*sphi*sphi; @@ -230,6 +244,10 @@ static PJ_XYZ forward_3d(PJ_LPZ lpz, PJ *P) { } else { lpz = calc_standard_params(lpz, P); } + if( lpz.lam == HUGE_VAL ) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return proj_coord_error().xyz; + } /* offset coordinate */ point.lpz.phi += lpz.phi; @@ -258,6 +276,11 @@ static PJ_LPZ reverse_3d(PJ_XYZ xyz, PJ *P) { else lpz = calc_standard_params(point.lpz, P); + if( lpz.lam == HUGE_VAL ) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return proj_coord_error().lpz; + } + /* offset coordinate */ point.lpz.phi -= lpz.phi; point.lpz.lam -= lpz.lam; diff --git a/src/transformations/vgridshift.cpp b/src/transformations/vgridshift.cpp index fda38ec3..de0cdd8c 100644 --- a/src/transformations/vgridshift.cpp +++ b/src/transformations/vgridshift.cpp @@ -6,7 +6,6 @@ #include <time.h> #include "proj_internal.h" -#include "proj_internal.h" PROJ_HEAD(vgridshift, "Vertical grid shift"); @@ -26,7 +25,7 @@ static PJ_XYZ forward_3d(PJ_LPZ lpz, PJ *P) { if (P->vgridlist_geoid != nullptr) { /* Only try the gridshift if at least one grid is loaded, * otherwise just pass the coordinate through unchanged. */ - point.xyz.z += Q->forward_multiplier * proj_vgrid_value(P, point.lp); + point.xyz.z += proj_vgrid_value(P, point.lp, Q->forward_multiplier); } return point.xyz; @@ -41,7 +40,7 @@ static PJ_LPZ reverse_3d(PJ_XYZ xyz, PJ *P) { if (P->vgridlist_geoid != nullptr) { /* Only try the gridshift if at least one grid is loaded, * otherwise just pass the coordinate through unchanged. */ - point.xyz.z -= Q->forward_multiplier * proj_vgrid_value(P, point.lp); + point.xyz.z -= proj_vgrid_value(P, point.lp, Q->forward_multiplier); } return point.lpz; diff --git a/src/wkt2_generated_parser.c b/src/wkt2_generated_parser.c index f6b1f6b1..b3a9eb24 100644 --- a/src/wkt2_generated_parser.c +++ b/src/wkt2_generated_parser.c @@ -211,76 +211,77 @@ extern int pj_wkt2_debug; T_COORDEPOCH = 330, T_COORDINATEMETADATA = 331, T_POINTMOTIONOPERATION = 332, - T_GEODETICCRS = 333, - T_GEODETICDATUM = 334, - T_PROJECTEDCRS = 335, - T_PRIMEMERIDIAN = 336, - T_GEOGRAPHICCRS = 337, - T_TRF = 338, - T_VERTICALCRS = 339, - T_VERTICALDATUM = 340, - T_VRF = 341, - T_TIMEDATUM = 342, - T_TEMPORALQUANTITY = 343, - T_ENGINEERINGDATUM = 344, - T_ENGINEERINGCRS = 345, - T_PARAMETRICDATUM = 346, - T_AFFINE = 347, - T_CARTESIAN = 348, - T_CYLINDRICAL = 349, - T_ELLIPSOIDAL = 350, - T_LINEAR = 351, - T_PARAMETRIC = 352, - T_POLAR = 353, - T_SPHERICAL = 354, - T_VERTICAL = 355, - T_TEMPORAL = 356, - T_TEMPORALCOUNT = 357, - T_TEMPORALMEASURE = 358, - T_ORDINAL = 359, - T_TEMPORALDATETIME = 360, - T_NORTH = 361, - T_NORTHNORTHEAST = 362, - T_NORTHEAST = 363, - T_EASTNORTHEAST = 364, - T_EAST = 365, - T_EASTSOUTHEAST = 366, - T_SOUTHEAST = 367, - T_SOUTHSOUTHEAST = 368, - T_SOUTH = 369, - T_SOUTHSOUTHWEST = 370, - T_SOUTHWEST = 371, - T_WESTSOUTHWEST = 372, - T_WEST = 373, - T_WESTNORTHWEST = 374, - T_NORTHWEST = 375, - T_NORTHNORTHWEST = 376, - T_UP = 377, - T_DOWN = 378, - T_GEOCENTRICX = 379, - T_GEOCENTRICY = 380, - T_GEOCENTRICZ = 381, - T_COLUMNPOSITIVE = 382, - T_COLUMNNEGATIVE = 383, - T_ROWPOSITIVE = 384, - T_ROWNEGATIVE = 385, - T_DISPLAYRIGHT = 386, - T_DISPLAYLEFT = 387, - T_DISPLAYUP = 388, - T_DISPLAYDOWN = 389, - T_FORWARD = 390, - T_AFT = 391, - T_PORT = 392, - T_STARBOARD = 393, - T_CLOCKWISE = 394, - T_COUNTERCLOCKWISE = 395, - T_TOWARDS = 396, - T_AWAYFROM = 397, - T_FUTURE = 398, - T_PAST = 399, - T_UNSPECIFIED = 400, - T_STRING = 401, - T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE = 402 + T_VERSION = 333, + T_GEODETICCRS = 334, + T_GEODETICDATUM = 335, + T_PROJECTEDCRS = 336, + T_PRIMEMERIDIAN = 337, + T_GEOGRAPHICCRS = 338, + T_TRF = 339, + T_VERTICALCRS = 340, + T_VERTICALDATUM = 341, + T_VRF = 342, + T_TIMEDATUM = 343, + T_TEMPORALQUANTITY = 344, + T_ENGINEERINGDATUM = 345, + T_ENGINEERINGCRS = 346, + T_PARAMETRICDATUM = 347, + T_AFFINE = 348, + T_CARTESIAN = 349, + T_CYLINDRICAL = 350, + T_ELLIPSOIDAL = 351, + T_LINEAR = 352, + T_PARAMETRIC = 353, + T_POLAR = 354, + T_SPHERICAL = 355, + T_VERTICAL = 356, + T_TEMPORAL = 357, + T_TEMPORALCOUNT = 358, + T_TEMPORALMEASURE = 359, + T_ORDINAL = 360, + T_TEMPORALDATETIME = 361, + T_NORTH = 362, + T_NORTHNORTHEAST = 363, + T_NORTHEAST = 364, + T_EASTNORTHEAST = 365, + T_EAST = 366, + T_EASTSOUTHEAST = 367, + T_SOUTHEAST = 368, + T_SOUTHSOUTHEAST = 369, + T_SOUTH = 370, + T_SOUTHSOUTHWEST = 371, + T_SOUTHWEST = 372, + T_WESTSOUTHWEST = 373, + T_WEST = 374, + T_WESTNORTHWEST = 375, + T_NORTHWEST = 376, + T_NORTHNORTHWEST = 377, + T_UP = 378, + T_DOWN = 379, + T_GEOCENTRICX = 380, + T_GEOCENTRICY = 381, + T_GEOCENTRICZ = 382, + T_COLUMNPOSITIVE = 383, + T_COLUMNNEGATIVE = 384, + T_ROWPOSITIVE = 385, + T_ROWNEGATIVE = 386, + T_DISPLAYRIGHT = 387, + T_DISPLAYLEFT = 388, + T_DISPLAYUP = 389, + T_DISPLAYDOWN = 390, + T_FORWARD = 391, + T_AFT = 392, + T_PORT = 393, + T_STARBOARD = 394, + T_CLOCKWISE = 395, + T_COUNTERCLOCKWISE = 396, + T_TOWARDS = 397, + T_AWAYFROM = 398, + T_FUTURE = 399, + T_PAST = 400, + T_UNSPECIFIED = 401, + T_STRING = 402, + T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE = 403 }; #endif @@ -541,21 +542,21 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 105 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 3221 +#define YYLAST 3309 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 163 +#define YYNTOKENS 164 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 339 +#define YYNNTS 350 /* YYNRULES -- Number of rules. */ -#define YYNRULES 670 +#define YYNRULES 687 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 1371 +#define YYNSTATES 1411 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 402 +#define YYMAXUTOK 403 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -568,12 +569,12 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 159, 161, 2, 153, 162, 154, 148, 2, 2, 150, - 151, 152, 2, 2, 2, 2, 2, 2, 155, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 149, + 160, 162, 2, 154, 163, 155, 149, 2, 2, 151, + 152, 153, 2, 2, 2, 2, 2, 2, 156, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 150, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 156, 2, 2, 2, 2, 2, - 157, 158, 2, 160, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 157, 2, 2, 2, 2, 2, + 158, 159, 2, 161, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -604,81 +605,82 @@ static const yytype_uint8 yytranslate[] = 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, 147 + 145, 146, 147, 148 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 206, 206, 206, 206, 206, 206, 206, 207, 207, - 207, 208, 211, 211, 212, 212, 212, 213, 215, 215, - 219, 223, 223, 225, 227, 229, 229, 231, 231, 233, - 235, 237, 239, 241, 241, 243, 243, 245, 245, 245, - 245, 247, 247, 251, 253, 257, 258, 259, 261, 261, - 263, 265, 267, 269, 273, 274, 277, 278, 280, 282, - 284, 287, 288, 289, 291, 293, 295, 295, 297, 300, - 301, 303, 303, 308, 308, 310, 310, 312, 314, 316, - 320, 321, 324, 325, 326, 328, 328, 329, 332, 333, - 337, 338, 339, 343, 344, 345, 346, 348, 352, 354, - 357, 359, 362, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 379, 380, 381, - 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, - 392, 393, 397, 399, 401, 405, 410, 412, 414, 416, - 418, 422, 427, 428, 430, 432, 434, 438, 442, 444, - 444, 446, 446, 451, 456, 457, 458, 459, 460, 461, - 462, 464, 466, 468, 468, 470, 470, 472, 474, 476, - 478, 480, 482, 486, 488, 492, 492, 495, 498, 503, - 503, 503, 503, 503, 506, 511, 511, 511, 511, 514, - 518, 519, 521, 537, 541, 542, 544, 544, 546, 546, - 552, 552, 554, 556, 563, 563, 563, 565, 572, 573, - 574, 575, 577, 584, 591, 592, 593, 595, 597, 597, - 597, 597, 597, 597, 597, 597, 597, 600, 600, 600, - 602, 602, 604, 604, 604, 606, 611, 617, 622, 625, - 628, 629, 630, 631, 632, 633, 634, 635, 636, 639, - 640, 641, 642, 643, 644, 645, 646, 649, 650, 651, - 652, 653, 654, 655, 656, 659, 660, 663, 664, 665, - 666, 671, 672, 673, 674, 675, 676, 677, 678, 679, - 682, 683, 684, 685, 688, 689, 690, 691, 694, 695, - 698, 699, 704, 705, 708, 709, 710, 711, 714, 715, - 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, - 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, - 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, - 746, 747, 748, 749, 751, 754, 756, 758, 760, 762, - 764, 780, 780, 782, 790, 791, 793, 794, 796, 804, - 805, 807, 809, 811, 816, 817, 819, 821, 823, 825, - 827, 829, 831, 836, 840, 842, 845, 848, 849, 850, - 852, 853, 855, 860, 861, 863, 863, 865, 869, 869, - 869, 871, 871, 873, 881, 890, 898, 908, 909, 911, - 913, 913, 915, 915, 918, 919, 923, 929, 930, 931, - 933, 933, 935, 937, 939, 943, 948, 948, 950, 953, - 954, 958, 963, 963, 963, 965, 967, 968, 969, 970, - 972, 975, 977, 981, 987, 987, 991, 991, 992, 992, - 994, 999, 1000, 1001, 1002, 1004, 1010, 1015, 1021, 1023, - 1025, 1027, 1031, 1037, 1038, 1039, 1041, 1043, 1045, 1049, - 1049, 1051, 1053, 1058, 1059, 1061, 1063, 1065, 1067, 1071, - 1071, 1073, 1079, 1086, 1086, 1089, 1096, 1097, 1098, 1099, - 1100, 1102, 1106, 1108, 1110, 1110, 1114, 1119, 1119, 1119, - 1123, 1128, 1128, 1130, 1134, 1134, 1138, 1143, 1145, 1149, - 1149, 1153, 1158, 1160, 1164, 1165, 1166, 1167, 1168, 1170, - 1170, 1172, 1175, 1177, 1177, 1179, 1181, 1183, 1187, 1193, - 1194, 1195, 1196, 1198, 1200, 1204, 1209, 1211, 1214, 1219, - 1223, 1229, 1229, 1229, 1229, 1229, 1229, 1233, 1238, 1240, - 1245, 1245, 1246, 1248, 1248, 1250, 1257, 1257, 1259, 1266, - 1266, 1268, 1275, 1282, 1287, 1288, 1290, 1296, 1301, 1309, - 1315, 1317, 1319, 1324, 1326, 1326, 1327, 1327, 1331, 1337, - 1337, 1339, 1342, 1346, 1351, 1357, 1360, 1365, 1371, 1374, - 1379, 1385, 1388, 1393, 1399, 1399, 1400, 1400, 1401, 1401, - 1402, 1402, 1403, 1403, 1404, 1404, 1407, 1407, 1409, 1410, - 1411, 1413, 1415, 1419, 1422, 1422, 1425, 1426, 1427, 1429, - 1433, 1434, 1436, 1438, 1438, 1439, 1439, 1440, 1440, 1440, - 1441, 1442, 1442, 1443, 1443, 1444, 1444, 1446, 1446, 1447, - 1447, 1448, 1449, 1449, 1453, 1459, 1460, 1461, 1462, 1463, - 1464, 1465, 1467, 1469, 1471, 1473, 1475, 1477, 1479, 1481, - 1483, 1485, 1490, 1496, 1497, 1498, 1499, 1500, 1502, 1507, - 1515, 1515, 1515, 1515, 1517, 1518, 1519, 1520, 1522, 1524, - 1529, 1535, 1537, 1544, 1544, 1546, 1547, 1548, 1549, 1551, - 1553 + 0, 207, 207, 207, 207, 207, 207, 207, 208, 208, + 208, 209, 212, 212, 213, 213, 213, 214, 216, 216, + 220, 224, 224, 226, 228, 230, 230, 232, 232, 234, + 236, 238, 240, 242, 242, 244, 244, 246, 246, 246, + 246, 248, 248, 252, 254, 258, 259, 260, 262, 262, + 264, 266, 268, 270, 274, 275, 278, 279, 281, 283, + 285, 288, 289, 290, 292, 294, 296, 296, 298, 301, + 302, 304, 304, 309, 309, 311, 311, 313, 315, 317, + 321, 322, 325, 326, 327, 329, 329, 330, 333, 334, + 338, 339, 340, 344, 345, 346, 347, 349, 353, 355, + 358, 360, 363, 364, 365, 366, 367, 368, 369, 370, + 371, 372, 373, 374, 375, 376, 377, 380, 381, 382, + 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, + 393, 394, 398, 400, 402, 406, 411, 413, 415, 417, + 419, 423, 428, 429, 431, 433, 435, 439, 443, 445, + 445, 447, 447, 452, 457, 458, 459, 460, 461, 462, + 463, 465, 467, 469, 469, 471, 471, 473, 475, 477, + 479, 481, 483, 487, 489, 493, 493, 496, 499, 504, + 504, 504, 504, 504, 507, 512, 512, 512, 512, 515, + 519, 520, 522, 538, 542, 543, 545, 545, 547, 547, + 553, 553, 555, 557, 564, 564, 564, 566, 573, 574, + 575, 576, 578, 585, 592, 593, 594, 596, 598, 598, + 598, 598, 598, 598, 598, 598, 598, 601, 601, 601, + 603, 603, 605, 605, 605, 607, 612, 618, 623, 626, + 629, 630, 631, 632, 633, 634, 635, 636, 637, 640, + 641, 642, 643, 644, 645, 646, 647, 650, 651, 652, + 653, 654, 655, 656, 657, 660, 661, 664, 665, 666, + 667, 672, 673, 674, 675, 676, 677, 678, 679, 680, + 683, 684, 685, 686, 689, 690, 691, 692, 695, 696, + 699, 700, 705, 706, 709, 710, 711, 712, 715, 716, + 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, + 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, + 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, + 747, 748, 749, 750, 752, 755, 757, 759, 761, 763, + 765, 781, 781, 783, 791, 792, 794, 795, 797, 805, + 806, 808, 810, 812, 817, 818, 820, 822, 824, 826, + 828, 830, 832, 837, 841, 843, 846, 849, 850, 851, + 853, 854, 856, 861, 862, 864, 864, 866, 870, 870, + 870, 872, 872, 874, 882, 891, 899, 909, 910, 912, + 914, 914, 916, 916, 919, 920, 924, 930, 931, 932, + 934, 934, 936, 938, 940, 944, 949, 949, 951, 954, + 955, 959, 964, 964, 964, 966, 968, 969, 970, 971, + 973, 976, 978, 982, 988, 988, 992, 992, 993, 993, + 995, 1000, 1001, 1002, 1003, 1004, 1006, 1012, 1017, 1023, + 1025, 1027, 1029, 1033, 1039, 1040, 1041, 1043, 1045, 1047, + 1051, 1051, 1053, 1055, 1060, 1061, 1063, 1065, 1067, 1069, + 1073, 1073, 1075, 1081, 1088, 1088, 1091, 1098, 1099, 1100, + 1101, 1102, 1104, 1108, 1110, 1112, 1112, 1116, 1121, 1121, + 1121, 1125, 1130, 1130, 1132, 1136, 1136, 1140, 1145, 1147, + 1151, 1151, 1155, 1160, 1162, 1166, 1167, 1168, 1169, 1170, + 1172, 1172, 1174, 1177, 1179, 1179, 1181, 1183, 1185, 1189, + 1195, 1196, 1197, 1198, 1200, 1202, 1206, 1211, 1213, 1216, + 1221, 1225, 1231, 1231, 1231, 1231, 1231, 1231, 1235, 1240, + 1242, 1247, 1247, 1248, 1250, 1250, 1252, 1259, 1259, 1261, + 1268, 1268, 1270, 1277, 1284, 1289, 1290, 1291, 1293, 1299, + 1304, 1312, 1318, 1320, 1322, 1328, 1330, 1330, 1331, 1331, + 1335, 1341, 1341, 1343, 1348, 1354, 1359, 1365, 1370, 1375, + 1381, 1386, 1391, 1397, 1402, 1407, 1413, 1413, 1414, 1414, + 1415, 1415, 1416, 1416, 1417, 1417, 1418, 1418, 1421, 1421, + 1423, 1424, 1425, 1427, 1429, 1433, 1436, 1436, 1439, 1440, + 1441, 1443, 1447, 1448, 1450, 1452, 1452, 1453, 1453, 1454, + 1454, 1454, 1455, 1456, 1456, 1457, 1457, 1458, 1458, 1460, + 1460, 1461, 1461, 1462, 1463, 1463, 1467, 1471, 1472, 1475, + 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1488, 1490, 1492, + 1495, 1497, 1499, 1501, 1503, 1505, 1507, 1509, 1511, 1513, + 1518, 1522, 1523, 1526, 1531, 1532, 1533, 1534, 1535, 1537, + 1542, 1547, 1548, 1551, 1557, 1557, 1557, 1557, 1559, 1560, + 1561, 1562, 1564, 1566, 1571, 1577, 1579, 1584, 1585, 1588, + 1594, 1594, 1596, 1597, 1598, 1599, 1601, 1603 }; #endif @@ -707,13 +709,13 @@ static const char *const yytname[] = "\"PARAMETRICCRS\"", "\"PARAMETRICUNIT\"", "\"BASEVERTCRS\"", "\"BASEENGCRS\"", "\"BASEPARAMCRS\"", "\"BASETIMECRS\"", "\"EPOCH\"", "\"COORDEPOCH\"", "\"COORDINATEMETADATA\"", "\"POINTMOTIONOPERATION\"", - "\"GEODETICCRS\"", "\"GEODETICDATUM\"", "\"PROJECTEDCRS\"", - "\"PRIMEMERIDIAN\"", "\"GEOGRAPHICCRS\"", "\"TRF\"", "\"VERTICALCRS\"", - "\"VERTICALDATUM\"", "\"VRF\"", "\"TIMEDATUM\"", "\"TEMPORALQUANTITY\"", - "\"ENGINEERINGDATUM\"", "\"ENGINEERINGCRS\"", "\"PARAMETRICDATUM\"", - "\"affine\"", "\"Cartesian\"", "\"cylindrical\"", "\"ellipsoidal\"", - "\"linear\"", "\"parametric\"", "\"polar\"", "\"spherical\"", - "\"vertical\"", "\"temporal\"", "\"temporalCount\"", + "\"VERSION\"", "\"GEODETICCRS\"", "\"GEODETICDATUM\"", + "\"PROJECTEDCRS\"", "\"PRIMEMERIDIAN\"", "\"GEOGRAPHICCRS\"", "\"TRF\"", + "\"VERTICALCRS\"", "\"VERTICALDATUM\"", "\"VRF\"", "\"TIMEDATUM\"", + "\"TEMPORALQUANTITY\"", "\"ENGINEERINGDATUM\"", "\"ENGINEERINGCRS\"", + "\"PARAMETRICDATUM\"", "\"affine\"", "\"Cartesian\"", "\"cylindrical\"", + "\"ellipsoidal\"", "\"linear\"", "\"parametric\"", "\"polar\"", + "\"spherical\"", "\"vertical\"", "\"temporal\"", "\"temporalCount\"", "\"temporalMeasure\"", "\"ordinal\"", "\"temporalDateTime\"", "\"north\"", "\"northNorthEast\"", "\"northEast\"", "\"eastNorthEast\"", "\"east\"", "\"eastSouthEast\"", "\"southEast\"", "\"southSouthEast\"", @@ -819,12 +821,12 @@ static const char *const yytname[] = "opt_separator_datum_anchor_identifier_list", "datum_anchor", "datum_anchor_keyword", "datum_anchor_description", "projected_crs", "projected_crs_keyword", "base_geodetic_crs", "base_static_geodetic_crs", - "opt_separator_pm_ellipsoidal_cs_unit", "base_dynamic_geodetic_crs", - "base_static_geographic_crs", "base_dynamic_geographic_crs", - "base_geodetic_crs_keyword", "base_geographic_crs_keyword", - "base_crs_name", "ellipsoidal_cs_unit", "map_projection", - "opt_separator_parameter_list_identifier_list", "map_projection_keyword", - "map_projection_name", "map_projection_method", + "opt_separator_pm_ellipsoidal_cs_unit_opt_separator_identifier_list", + "base_dynamic_geodetic_crs", "base_static_geographic_crs", + "base_dynamic_geographic_crs", "base_geodetic_crs_keyword", + "base_geographic_crs_keyword", "base_crs_name", "ellipsoidal_cs_unit", + "map_projection", "opt_separator_parameter_list_identifier_list", + "map_projection_keyword", "map_projection_name", "map_projection_method", "map_projection_method_keyword", "map_projection_method_name", "map_projection_parameter", "opt_separator_param_unit_identifier_list", "parameter_keyword", "parameter_name", "parameter_value", @@ -857,10 +859,10 @@ static const char *const yytname[] = "derived_dynamic_geod_crs", "base_dynamic_geod_crs_or_base_dynamic_geog_crs", "derived_static_geog_crs", "derived_dynamic_geog_crs", - "base_static_geod_crs", "opt_separator_pm", "base_dynamic_geod_crs", - "base_static_geog_crs", "base_dynamic_geog_crs", "derived_projected_crs", - "derived_projected_crs_keyword", "derived_crs_name", - "base_projected_crs", "base_projected_crs_keyword", + "base_static_geod_crs", "opt_separator_pm_opt_separator_identifier_list", + "base_dynamic_geod_crs", "base_static_geog_crs", "base_dynamic_geog_crs", + "derived_projected_crs", "derived_projected_crs_keyword", + "derived_crs_name", "base_projected_crs", "base_projected_crs_keyword", "base_geodetic_geographic_crs", "derived_vertical_crs", "base_vertical_crs", "base_static_vertical_crs", "base_dynamic_vertical_crs", "base_vertical_crs_keyword", @@ -874,17 +876,23 @@ static const char *const yytname[] = "coordinate_epoch_keyword", "coordinate_epoch", "coordinate_metadata", "coordinate_metadata_crs", "coordinate_metadata_keyword", "static_crs_coordinate_metadata", "dynamic_crs_coordinate_metadata", - "coordinate_operation", + "coordinate_operation", "coordinate_operation_next", + "coordinate_operation_end", "opt_parameter_or_parameter_file_list_opt_interpolation_crs_opt_operation_accuracy_opt_separator_scope_extent_identifier_remark", - "operation_keyword", "operation_name", "source_crs", + "operation_keyword", "operation_name", "operation_version", + "operation_version_keyword", "operation_version_text", "source_crs", "source_crs_keyword", "target_crs", "target_crs_keyword", "interpolation_crs", "interpolation_crs_keyword", "operation_accuracy", "operation_accuracy_keyword", "point_motion_operation", + "point_motion_operation_next", "point_motion_operation_end", "opt_parameter_or_parameter_file_list_opt_operation_accuracy_opt_separator_scope_extent_identifier_remark", - "point_motion_keyword", "concatenated_operation", "step", + "point_motion_keyword", "concatenated_operation", + "concatenated_operation_next", "concatenated_operation_end", "step", "opt_concatenated_operation_end", "concatenated_operation_keyword", "step_keyword", "bound_crs", "bound_crs_keyword", "abridged_coordinate_transformation", + "abridged_coordinate_transformation_next", + "abridged_coordinate_transformation_end", "abridged_parameter_or_parameter_file", "opt_end_abridged_coordinate_transformation", "abridged_transformation_keyword", "abridged_transformation_parameter", YY_NULLPTR @@ -910,18 +918,18 @@ static const yytype_uint16 yytoknum[] = 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 401, 402, 46, 69, - 49, 50, 51, 43, 45, 58, 84, 90, 91, 40, - 93, 41, 44 + 395, 396, 397, 398, 399, 400, 401, 402, 403, 46, + 69, 49, 50, 51, 43, 45, 58, 84, 90, 91, + 40, 93, 41, 44 }; # endif -#define YYPACT_NINF -1145 +#define YYPACT_NINF -1187 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-1145))) + (!!((Yystate) == (-1187))) -#define YYTABLE_NINF -624 +#define YYTABLE_NINF -626 #define yytable_value_is_error(Yytable_value) \ 0 @@ -930,144 +938,148 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int16 yypact[] = { - 799, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, - -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, - -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, - -1145, -1145, -1145, -1145, -1145, -1145, -1145, 132, -1145, -1145, - -1145, 304, -1145, -1145, -1145, 304, -1145, -1145, -1145, -1145, - -1145, -1145, 304, 304, -1145, 304, -1145, 304, -1145, 304, - -1145, 304, -1145, -1145, -1145, 304, -1145, 304, -1145, 304, - -1145, 304, -1145, 304, -1145, 304, -1145, 304, -1145, 304, - -1145, -1145, -1145, -1145, -1145, -1145, -1145, 304, -1145, -1145, - -1145, -1145, -1145, -1145, 304, -1145, 304, -1145, 304, -1145, - 304, -1145, 304, -1145, 304, -1145, -1145, -1145, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 1044, 30, 30, 30, - 170, -1145, -1145, 61, -1145, 61, -1145, 61, 61, -1145, - 61, -1145, 61, 61, -1145, 61, 61, 61, 61, 61, - 61, 61, 61, 61, -1145, 61, -1145, 61, -1145, -1145, - -1145, -1145, 78, -1145, -1145, -1145, -1145, -1145, 148, 229, - 241, -1145, -1145, -1145, -1145, 315, -1145, 61, -1145, 61, - 61, 61, -1145, 61, 304, -1145, 922, 284, 445, 445, - 577, 345, 279, 321, 412, 342, 315, 250, 315, 393, - 315, 67, 280, 315, 351, 1285, -1145, -1145, -1145, 446, - 170, 170, 170, 381, 1044, -1145, -1145, -1145, -1145, -1145, - -1145, -1145, 624, -1145, -1145, -1145, -1145, 299, 302, 307, - 577, -1145, 61, -1145, 61, 304, -1145, -1145, -1145, -1145, - 304, 61, 304, 61, -1145, 304, 304, 61, 61, -1145, - -1145, -1145, -1145, 61, 61, 61, 61, -1145, 61, 61, - 61, -1145, -1145, -1145, -1145, 304, 304, -1145, -1145, 61, - 304, -1145, -1145, 304, 61, 61, -1145, 61, -1145, -1145, - 304, -1145, 61, 61, 304, -1145, -1145, 61, 61, 304, - -1145, -1145, 61, 61, 304, -1145, -1145, 61, 61, 304, - -1145, -1145, 61, 61, 304, 61, 304, -1145, -1145, 61, - 304, -1145, 61, -1145, -1145, -1145, -1145, 304, 61, 61, - 61, -1145, 61, 304, 315, -1145, 400, 624, -1145, -1145, - 365, 315, 122, 315, 315, 30, 30, 115, 402, 127, - 30, 30, 419, 419, 115, 127, 419, 419, 577, 315, - 456, 30, 30, 423, 315, 30, 30, 189, 480, 419, - 30, 490, -1145, 490, 30, 480, 419, 30, 480, 419, - 30, 480, 419, 30, -1145, -1145, 506, 146, -1145, 30, - 419, 30, 1285, 624, 381, 485, 381, 487, 1044, -1145, - 624, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, 61, - 61, 304, -1145, 304, -1145, -1145, 61, 61, 304, 61, - -1145, -1145, -1145, 61, 61, 61, -1145, 61, 304, -1145, - -1145, -1145, -1145, -1145, -1145, -1145, 304, 315, 61, 304, - -1145, 61, 61, -1145, 61, 304, 61, 61, 315, 61, - 61, -1145, 61, -1145, 61, 61, 61, -1145, 61, 61, - 304, -1145, -1145, 61, 61, 61, 304, 315, 61, 61, - 61, 61, -1145, 315, 315, 61, 61, 315, 61, 61, - 315, 61, 61, -1145, -1145, 376, -1145, 315, 61, -1145, - 315, 61, 61, 61, 307, 315, 61, -1145, 61, 304, - 61, -1145, 61, 304, 315, -1145, 510, 505, 30, 30, - -1145, -1145, 490, -1145, 752, 515, 490, 315, 284, 127, - 532, 315, 624, 1049, -1145, 480, 30, 272, 272, 480, - 30, 480, 127, -1145, 480, 480, 470, 315, 480, 272, - 272, -1145, -1145, 30, 315, 284, 480, 1313, -1145, 480, - 106, -1145, -1145, -1145, -1145, 480, 100, -1145, 480, 152, - -1145, 480, 74, -1145, -1145, 624, -1145, -1145, 624, -1145, - -1145, -1145, 480, 279, 953, 315, 624, -1145, 485, 1361, - 315, 30, 502, 843, 315, 30, -1145, 61, -1145, -1145, - 315, -1145, 315, -1145, 61, -1145, 315, 61, -1145, 61, - -1145, 61, 315, -1145, -1145, -1145, 304, -1145, 307, 315, - -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, - -1145, -1145, -1145, -1145, 61, 61, 61, -1145, -1145, 61, - 61, 61, 61, 61, 315, -1145, 61, 315, 315, 315, - 315, -1145, -1145, 61, 61, 304, -1145, 315, 61, 61, - 61, 61, -1145, 61, -1145, 61, 315, 61, 315, 61, - 315, 315, 315, 315, 315, 315, 315, 428, 418, -1145, - 534, 315, -1145, -1145, -1145, -1145, 61, -1145, -1145, -1145, - -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, 61, 304, - 61, 304, -1145, 61, 304, 61, 304, 61, 304, 61, - 304, 61, -1145, 304, 61, -1145, -1145, 61, -1145, -1145, - -1145, 304, 61, 61, 304, 61, 304, -1145, -1145, 61, - -1145, 304, -1145, -1145, 61, 505, -1145, -1145, -1145, -1145, - -1145, -1145, 110, -1145, 30, 624, -1145, 409, 409, 409, - 400, 115, 89, 315, 115, 315, -1145, 485, -1145, -1145, - -1145, -1145, -1145, -1145, 30, -1145, 115, 105, 315, 115, - 315, 400, 569, -1145, 409, -1145, 189, -1145, -1145, -1145, - -1145, -1145, -1145, -1145, -1145, 624, -1145, -1145, 624, 624, - -1145, 431, -1145, -1145, -1145, -1145, 456, 130, 566, 469, - -1145, 30, 340, -1145, 30, 183, -1145, 752, 282, -1145, - 752, 335, -1145, 506, -1145, 453, -1145, 1330, 315, 30, - -1145, -1145, 30, -1145, 752, 490, 315, 90, 485, -1145, - 61, -1145, 61, -1145, -1145, -1145, -1145, 61, 61, 61, - 61, 577, 315, 61, -1145, -1145, 61, -1145, 61, -1145, - 61, 61, -1145, -1145, -1145, 304, 61, -1145, -1145, 61, - -1145, -1145, 61, 61, 61, 315, -1145, 449, 431, -1145, - 534, 624, -1145, 315, -1145, 61, -1145, 61, -1145, 61, - -1145, -1145, 315, 61, 61, 61, -1145, 315, 61, 61, - -1145, 61, 61, -1145, 61, -1145, -1145, 61, -1145, 315, - -1145, -1145, 61, 61, 61, 304, 61, -1145, 61, 61, - 315, -1145, -1145, -1145, -1145, -1145, -1145, 315, 61, 315, - 315, 315, 315, 497, -1145, -1145, -1145, 315, 315, 339, - 315, 577, 315, 30, 157, 315, 616, 315, 315, -1145, - -1145, -1145, 624, -1145, -1145, -1145, -1145, -1145, 273, -1145, - -1145, 183, -1145, 282, -1145, -1145, -1145, 282, -1145, -1145, - 752, -1145, 752, 506, -1145, -1145, -1145, 801, -1145, 1044, - -1145, 400, 30, -1145, 61, 221, -1145, 61, 61, 61, - 61, -1145, -1145, 61, 61, 61, -1145, -1145, 61, -1145, - 61, -1145, -1145, -1145, -1145, -1145, -1145, -1145, 304, 61, - -1145, 61, -1145, -1145, 802, 315, 61, 61, 61, -1145, - 61, 61, 61, 61, -1145, 61, -1145, 61, -1145, -1145, - 315, 61, 315, 61, -1145, 61, 502, 304, -1145, 61, - -1145, 599, 599, 599, -1145, -1145, -1145, -1145, 315, 577, - 30, -1145, 599, 761, -1145, -1145, 347, 583, 559, 282, - -1145, -1145, -1145, -1145, 752, 395, 315, -1145, -1145, -1145, - 305, 315, 304, 30, 1085, 315, -1145, 61, 304, 61, - 304, 61, 304, -1145, 61, 61, 61, 328, 761, -1145, - 61, 61, -1145, 61, -1145, -1145, 61, -1145, 61, -1145, - -1145, -1145, -1145, -1145, -1145, -1145, -1145, 61, -1145, 304, - -1145, 90, 61, -1145, 61, 61, -1145, 666, -1145, 30, - -1145, 30, 715, -1145, 30, 315, 577, 912, -1145, -1145, - 583, 559, 559, -1145, 752, 315, 30, 315, 400, -1145, - -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, - -1145, -1145, 304, -1145, 304, 61, 61, -1145, 61, 61, - -1145, 61, 61, -1145, 61, -1145, -1145, 61, 61, 304, - 61, -1145, -1145, -1145, -1145, 315, -1145, 61, 61, 61, - 30, 30, -1145, -1145, 1410, 1663, -1145, 1450, 315, 1160, - -1145, -1145, 30, 559, -1145, 577, 315, 943, 315, 315, - 61, 61, 61, -1145, -1145, -1145, -1145, -1145, -1145, -1145, - 61, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, - -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, - -1145, -1145, -1145, -1145, -1145, 61, 61, -1145, -1145, -1145, - -1145, -1145, 315, -1145, 61, 61, 61, 61, 61, 61, - 315, -1145, 61, -1145, 61, -1145, 61, -1145, 61, -1145, - -1145, 61, 304, -1145, -1145, 577, 315, 524, 524, 696, - 696, -1145, 597, 117, 315, 523, 524, 545, 545, -1145, - 358, -1145, 315, -1145, -1145, 90, 61, -1145, -1145, -1145, - 61, 61, -1145, 61, 304, 61, 304, -1145, -1145, 61, - 61, -1145, 61, 304, 61, -1145, 61, 61, -1145, 61, - 61, 61, -1145, 61, -1145, 61, -1145, 61, 61, -1145, - 61, -1145, 61, 61, -1145, 61, -1145, 61, -1145, 315, - 315, -1145, -1145, 597, -1145, 752, 397, -1145, 624, -1145, - -1145, 597, -1145, 752, 397, -1145, -1145, -1145, 397, -1145, - -1145, -1145, 134, -1145, -1145, 358, -1145, -1145, -1145, 358, - -1145, -1145, -1145, -1145, 61, -1145, 61, 61, 61, 61, - 315, 61, 61, 315, 61, 61, 61, 61, 61, -1145, - -1145, 397, -1145, 157, -1145, -1145, -1145, 397, -1145, -1145, - -1145, -1145, -1145, -1145, -1145, 61, 315, 61, -1145, -1145, - -1145 + 820, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, + -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, + -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, + -1187, -1187, -1187, -1187, -1187, -1187, -1187, 147, -1187, -1187, + -1187, 213, -1187, -1187, -1187, 213, -1187, -1187, -1187, -1187, + -1187, -1187, 213, 213, -1187, 213, -1187, 213, -1187, 213, + -1187, 213, -1187, -1187, -1187, 213, -1187, 213, -1187, 213, + -1187, 213, -1187, 213, -1187, 213, -1187, 213, -1187, 213, + -1187, -1187, -1187, -1187, -1187, -1187, -1187, 213, -1187, -1187, + -1187, -1187, -1187, -1187, 213, -1187, 213, -1187, 213, -1187, + 213, -1187, 213, -1187, 213, -1187, -1187, -1187, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 928, 19, 19, 19, + 164, -1187, -1187, 17, -1187, 17, -1187, 17, 17, -1187, + 17, -1187, 17, 17, -1187, 17, 17, 17, 17, 17, + 17, 17, 17, 17, -1187, 17, -1187, 17, -1187, -1187, + -1187, -1187, 78, -1187, -1187, -1187, -1187, -1187, 94, 167, + 185, -1187, -1187, -1187, -1187, 345, -1187, 17, -1187, 17, + 17, 17, -1187, 17, 213, -1187, 1290, 154, 97, 97, + 680, 330, 412, 301, 499, 113, 345, 304, 345, 312, + 345, 160, 255, 345, 231, 1501, -1187, -1187, -1187, 487, + 100, -1187, -1187, 100, -1187, -1187, 100, -1187, -1187, 382, + 928, -1187, -1187, -1187, -1187, -1187, -1187, -1187, 385, -1187, + -1187, -1187, -1187, 292, 299, 317, 680, -1187, 17, -1187, + 17, 213, -1187, -1187, -1187, -1187, 213, 17, 213, 17, + -1187, 213, 213, 17, 17, -1187, -1187, -1187, -1187, 17, + 17, 17, 17, -1187, 17, 17, 17, -1187, -1187, -1187, + -1187, 213, 213, -1187, -1187, 17, 213, -1187, -1187, 213, + 17, 17, -1187, 17, -1187, -1187, 213, -1187, 17, 17, + 213, -1187, -1187, 17, 17, 213, -1187, -1187, 17, 17, + 213, -1187, -1187, 17, 17, 213, -1187, -1187, 17, 17, + 213, 17, 213, -1187, -1187, 17, 213, -1187, 17, -1187, + -1187, -1187, -1187, 213, -1187, 17, 213, 17, 17, 17, + 17, 17, -1187, 17, 213, 345, -1187, 459, 385, -1187, + -1187, 329, 345, 157, 345, 345, 19, 19, 102, 422, + 112, 19, 19, 442, 442, 102, 112, 442, 442, 680, + 345, 470, 19, 19, 243, 345, 19, 19, 242, 496, + 442, 19, 486, -1187, 486, 19, 496, 442, 19, 496, + 442, 19, 496, 442, 19, -1187, -1187, 669, 107, -1187, + 19, 442, 19, 1501, 385, 164, -1187, 19, 382, 164, + -1187, 505, 164, -1187, 382, 493, 928, -1187, 385, -1187, + -1187, -1187, -1187, -1187, -1187, -1187, -1187, 17, 17, 213, + -1187, 213, -1187, -1187, 17, 17, 213, 17, -1187, -1187, + -1187, 17, 17, 17, -1187, 17, 213, -1187, -1187, -1187, + -1187, -1187, -1187, -1187, 213, 345, 17, 213, -1187, 17, + 17, -1187, 17, 213, 17, 17, 345, 17, 17, -1187, + 17, -1187, 17, 17, 17, -1187, 17, 17, 213, -1187, + -1187, 17, 17, 17, 213, 345, 17, 17, 17, 17, + -1187, 345, 345, 17, 17, 345, 17, 17, 345, 17, + 17, -1187, -1187, 363, -1187, 345, 17, -1187, 345, 17, + 17, 17, 317, 345, -1187, 345, 17, -1187, 17, 213, + 17, -1187, 17, 213, 345, -1187, 489, 514, 19, 19, + -1187, -1187, 486, -1187, 1298, 506, 486, 345, 154, 112, + 565, 345, 385, 1217, -1187, 496, 19, 90, 90, 496, + 19, 496, 112, -1187, 496, 496, 327, 345, 496, 90, + 90, -1187, -1187, 19, 345, 154, 496, 1258, -1187, 496, + 364, -1187, -1187, -1187, -1187, 496, 108, -1187, 496, 245, + -1187, 496, 72, -1187, -1187, 385, -1187, -1187, 385, -1187, + -1187, -1187, 496, 412, 1402, 345, 385, -1187, -1187, 505, + 694, 345, 19, 534, 1206, 345, 19, -1187, 17, -1187, + -1187, 345, -1187, 345, -1187, 17, -1187, 345, 17, -1187, + 17, -1187, 17, 345, -1187, -1187, -1187, 213, -1187, 317, + 345, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, + -1187, -1187, -1187, -1187, -1187, 17, 17, 17, -1187, -1187, + 17, 17, 17, 17, 17, 345, -1187, 17, 345, 345, + 345, 345, -1187, -1187, 17, 17, 213, -1187, 345, 17, + 17, 17, 17, -1187, 17, -1187, 17, 345, 17, 345, + 17, 17, 345, 17, 345, 17, 345, 17, 386, 427, + -1187, 635, 345, -1187, -1187, -1187, -1187, 17, -1187, -1187, + -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, 17, + 213, 17, 213, -1187, 17, 213, 17, 213, 17, 213, + 17, 213, 17, -1187, 213, 17, -1187, -1187, 17, -1187, + -1187, -1187, 213, 17, 17, 213, 17, 213, -1187, -1187, + 17, -1187, 213, -1187, -1187, 17, 514, -1187, -1187, -1187, + -1187, -1187, -1187, 140, -1187, 19, 385, -1187, 398, 398, + 398, 459, 102, 131, 345, 102, 345, -1187, 505, -1187, + -1187, -1187, -1187, -1187, -1187, 19, -1187, 102, 132, 345, + 102, 345, 459, 568, -1187, 398, -1187, 242, 345, -1187, + 345, -1187, 345, -1187, 345, -1187, 385, -1187, -1187, 385, + 385, -1187, 437, -1187, -1187, -1187, -1187, 470, 315, 572, + 754, -1187, 19, 527, -1187, 19, 323, -1187, 1298, 115, + -1187, 1298, 474, -1187, 669, -1187, 462, -1187, 688, 345, + 19, -1187, -1187, 19, -1187, 1298, 486, 345, 151, 101, + -1187, -1187, -1187, 17, -1187, 17, -1187, -1187, -1187, -1187, + 17, 17, 17, 17, 680, 345, 17, 17, 17, -1187, + 17, -1187, 17, -1187, 17, 17, -1187, -1187, 17, -1187, + 213, 17, 17, -1187, 17, -1187, -1187, 17, 17, 17, + 17, -1187, -1187, -1187, -1187, -1187, 449, 437, -1187, 635, + 385, -1187, 17, -1187, 17, -1187, 17, -1187, 17, -1187, + -1187, 345, 17, 17, 17, -1187, 345, 17, 17, -1187, + 17, 17, -1187, 17, -1187, -1187, 17, -1187, 345, -1187, + -1187, 17, 17, 17, 213, 17, -1187, 17, 17, 345, + -1187, -1187, -1187, -1187, -1187, -1187, 345, 17, 17, 345, + 345, 345, 345, 390, -1187, -1187, -1187, 345, -1187, -1187, + 345, 179, 345, 680, 345, -1187, 19, 390, -1187, -1187, + 345, 733, 345, 345, 345, -1187, -1187, 385, -1187, -1187, + -1187, 345, -1187, 457, -1187, -1187, 323, -1187, 115, -1187, + -1187, -1187, 115, -1187, -1187, 1298, -1187, 1298, 669, -1187, + -1187, -1187, 991, -1187, 928, -1187, 459, 19, -1187, 17, + 114, 505, -1187, -1187, 17, 17, 17, 17, -1187, -1187, + 17, 17, 17, -1187, -1187, 17, -1187, 17, 17, -1187, + -1187, -1187, -1187, -1187, -1187, 213, 17, -1187, 17, -1187, + -1187, -1187, 1034, -1187, 345, 17, 17, 17, -1187, 17, + 17, 17, 17, -1187, 17, -1187, 17, -1187, -1187, 345, + 17, 345, 17, -1187, 17, 534, 213, -1187, 17, -1187, + 596, 596, 596, -1187, -1187, -1187, -1187, 345, 680, -1187, + 19, -1187, 596, 1148, -1187, -1187, 190, 591, 557, 115, + -1187, -1187, -1187, -1187, 1298, 376, 345, -1187, -1187, -1187, + 287, 345, 213, 19, 972, 345, -1187, 17, 213, 17, + 213, 17, 213, -1187, 17, 17, 17, 204, 1148, -1187, + 17, 17, -1187, 17, -1187, -1187, 17, -1187, 17, -1187, + -1187, -1187, -1187, -1187, -1187, -1187, -1187, 17, -1187, 213, + -1187, 151, 17, -1187, 17, 17, -1187, 906, -1187, 19, + -1187, 19, 566, -1187, 19, 345, 680, 1240, -1187, -1187, + 591, 557, 557, -1187, 1298, 345, 19, 345, 459, -1187, + -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, + -1187, -1187, 213, -1187, 213, 17, 17, -1187, 17, 17, + -1187, 17, 17, -1187, 17, -1187, -1187, 17, 17, 213, + 17, -1187, -1187, -1187, -1187, 345, -1187, 17, 17, 17, + 19, 19, -1187, -1187, 1544, 1736, -1187, 1584, 345, 1080, + -1187, -1187, 19, 557, -1187, 680, 345, 899, 345, 345, + 17, 17, 17, -1187, -1187, -1187, -1187, -1187, -1187, -1187, + 17, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, + -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, + -1187, -1187, -1187, -1187, -1187, 17, 17, -1187, -1187, -1187, + -1187, -1187, 345, -1187, 17, 17, 17, 17, 17, 17, + 345, -1187, 17, -1187, 17, -1187, 17, -1187, 17, -1187, + -1187, 17, 213, -1187, -1187, 680, 345, 417, 417, 625, + 625, -1187, 605, 137, 345, 447, 417, 404, 404, -1187, + 476, -1187, 345, -1187, -1187, 151, 17, -1187, -1187, -1187, + 17, 17, -1187, 17, 213, 17, 213, -1187, -1187, 17, + 17, -1187, 17, 213, 17, -1187, 17, 17, -1187, 17, + 17, 17, -1187, 17, -1187, 17, -1187, 17, 17, -1187, + 17, -1187, 17, 17, -1187, 17, -1187, 17, -1187, 345, + 345, -1187, -1187, 605, -1187, 1298, 379, -1187, 385, -1187, + -1187, 605, -1187, 1298, 379, -1187, -1187, -1187, 379, -1187, + -1187, -1187, 103, -1187, -1187, 476, -1187, -1187, -1187, 476, + -1187, -1187, -1187, -1187, 17, -1187, 17, 17, 17, 17, + 345, 17, 17, 345, 17, 17, 17, 17, 17, -1187, + -1187, 379, -1187, 490, -1187, -1187, -1187, 379, -1187, -1187, + -1187, -1187, -1187, -1187, -1187, 17, 345, 17, -1187, -1187, + -1187 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -1075,141 +1087,145 @@ static const yytype_int16 yypact[] = means the default is an error. */ static const yytype_uint16 yydefact[] = { - 0, 412, 401, 390, 400, 161, 424, 446, 392, 474, - 477, 591, 632, 658, 661, 499, 492, 351, 550, 484, - 481, 489, 487, 602, 648, 391, 414, 425, 393, 413, - 475, 479, 478, 500, 485, 482, 490, 0, 4, 5, - 2, 0, 13, 341, 342, 0, 574, 380, 378, 379, - 381, 382, 0, 0, 3, 0, 12, 0, 576, 0, - 11, 0, 578, 459, 460, 0, 14, 0, 580, 0, - 15, 0, 582, 0, 16, 0, 584, 0, 17, 0, - 575, 532, 530, 531, 533, 534, 577, 0, 579, 581, - 583, 585, 19, 18, 0, 7, 0, 8, 0, 9, + 0, 412, 401, 390, 400, 161, 424, 447, 392, 475, + 478, 593, 637, 672, 675, 500, 493, 351, 552, 485, + 482, 490, 488, 604, 659, 391, 414, 425, 393, 413, + 476, 480, 479, 501, 486, 483, 491, 0, 4, 5, + 2, 0, 13, 341, 342, 0, 576, 380, 378, 379, + 381, 382, 0, 0, 3, 0, 12, 0, 578, 0, + 11, 0, 580, 460, 461, 0, 14, 0, 582, 0, + 15, 0, 584, 0, 16, 0, 586, 0, 17, 0, + 577, 533, 531, 532, 534, 535, 579, 0, 581, 583, + 585, 587, 19, 18, 0, 7, 0, 8, 0, 9, 0, 10, 0, 6, 0, 1, 73, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 162, 0, 352, 0, 389, 0, 0, 402, - 0, 415, 0, 0, 447, 0, 0, 416, 0, 416, - 0, 416, 0, 494, 551, 0, 592, 0, 603, 617, - 604, 618, 605, 606, 620, 607, 608, 609, 610, 611, - 612, 613, 614, 615, 616, 0, 600, 0, 633, 0, - 0, 0, 635, 0, 0, 77, 0, 0, 0, 0, + 0, 415, 0, 0, 448, 0, 0, 416, 0, 416, + 0, 416, 0, 495, 553, 0, 594, 0, 605, 619, + 606, 620, 607, 608, 622, 609, 610, 611, 612, 613, + 614, 615, 616, 617, 618, 0, 602, 0, 638, 0, + 0, 0, 643, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 75, 76, 599, 0, - 0, 0, 0, 0, 0, 40, 20, 37, 38, 39, - 41, 42, 0, 163, 21, 22, 26, 0, 25, 35, - 0, 164, 154, 356, 0, 0, 438, 439, 364, 395, - 0, 0, 0, 0, 394, 0, 0, 0, 0, 536, - 539, 537, 540, 0, 0, 0, 0, 403, 0, 416, - 0, 426, 427, 428, 429, 0, 0, 450, 449, 443, - 0, 563, 464, 0, 0, 0, 463, 0, 559, 560, - 0, 421, 190, 417, 0, 476, 566, 0, 0, 0, - 483, 569, 0, 0, 0, 488, 572, 0, 0, 0, - 506, 502, 190, 190, 0, 190, 0, 493, 553, 0, - 0, 586, 0, 587, 594, 595, 601, 0, 0, 0, - 0, 637, 0, 0, 0, 34, 27, 0, 33, 23, + 0, 0, 0, 0, 0, 0, 75, 76, 601, 0, + 0, 626, 628, 0, 650, 652, 0, 660, 662, 0, + 0, 40, 20, 37, 38, 39, 41, 42, 0, 163, + 21, 22, 26, 0, 25, 35, 0, 164, 154, 356, + 0, 0, 439, 440, 364, 395, 0, 0, 0, 0, + 394, 0, 0, 0, 0, 537, 540, 538, 541, 0, + 0, 0, 0, 403, 0, 416, 0, 426, 427, 428, + 429, 0, 0, 451, 450, 444, 0, 565, 465, 0, + 0, 0, 464, 0, 561, 562, 0, 421, 190, 417, + 0, 477, 568, 0, 0, 0, 484, 571, 0, 0, + 0, 489, 574, 0, 0, 0, 507, 503, 190, 190, + 0, 190, 0, 494, 555, 0, 0, 588, 0, 589, + 596, 597, 603, 0, 640, 0, 0, 0, 0, 0, + 0, 0, 645, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 418, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 498, 497, 0, 0, 495, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 634, - 0, 29, 31, 28, 36, 168, 171, 165, 166, 155, - 158, 0, 160, 0, 153, 360, 0, 346, 0, 0, - 343, 348, 357, 354, 0, 0, 366, 370, 0, 406, - 217, 407, 388, 204, 205, 206, 0, 0, 0, 0, - 440, 0, 0, 513, 0, 0, 0, 0, 0, 0, - 0, 404, 397, 411, 0, 0, 0, 455, 190, 443, - 0, 442, 451, 190, 0, 0, 0, 0, 0, 0, - 190, 190, 422, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 50, 503, 48, 504, 0, 190, 507, - 0, 0, 0, 588, 596, 0, 0, 516, 643, 0, - 0, 669, 80, 0, 0, 32, 0, 0, 0, 0, + 0, 0, 0, 418, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 499, 498, 0, 0, 496, + 0, 0, 0, 0, 0, 0, 627, 0, 0, 0, + 651, 0, 0, 661, 0, 0, 0, 642, 0, 29, + 31, 28, 36, 168, 171, 165, 166, 155, 158, 0, + 160, 0, 153, 360, 0, 346, 0, 0, 343, 348, + 357, 354, 0, 0, 366, 370, 0, 406, 217, 407, + 388, 204, 205, 206, 0, 0, 0, 0, 441, 0, + 0, 514, 0, 0, 0, 0, 0, 0, 0, 404, + 397, 411, 0, 0, 0, 456, 190, 444, 0, 443, + 452, 190, 0, 0, 0, 0, 0, 0, 190, 190, + 422, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 50, 504, 48, 505, 0, 190, 508, 0, 0, + 0, 590, 598, 0, 641, 0, 0, 517, 654, 0, + 0, 686, 80, 0, 0, 32, 0, 0, 0, 0, 345, 350, 0, 349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 383, 0, 0, 0, 0, 0, 0, 0, 0, 385, 0, 0, 0, 0, 0, 0, - 0, 444, 445, 0, 0, 0, 0, 0, 461, 0, - 0, 191, 419, 420, 480, 0, 0, 486, 0, 0, - 491, 0, 0, 44, 58, 0, 45, 49, 0, 501, - 496, 505, 0, 0, 0, 0, 597, 593, 0, 0, - 0, 0, 0, 0, 0, 0, 636, 156, 159, 169, - 0, 172, 0, 362, 346, 361, 0, 346, 358, 354, - 353, 0, 0, 375, 376, 371, 0, 363, 367, 0, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, 0, 0, 0, 387, 408, 0, - 0, 544, 0, 544, 0, 514, 0, 0, 0, 0, - 0, 199, 198, 190, 190, 0, 396, 0, 0, 431, - 0, 431, 456, 0, 448, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 48, 0, 59, - 0, 0, 554, 555, 556, 557, 0, 174, 100, 133, - 136, 144, 148, 98, 590, 82, 88, 89, 93, 0, - 85, 0, 92, 85, 0, 85, 0, 85, 0, 85, - 0, 85, 84, 0, 588, 573, 598, 625, 528, 641, - 647, 0, 643, 643, 0, 80, 0, 642, 517, 373, - 659, 0, 81, 660, 0, 0, 167, 170, 347, 359, - 344, 355, 0, 384, 0, 368, 365, 0, 0, 0, - 27, 0, 0, 0, 0, 0, 535, 0, 538, 386, - 541, 542, 399, 398, 0, 423, 0, 0, 0, 0, - 0, 27, 0, 462, 0, 558, 0, 561, 564, 565, - 567, 568, 570, 571, 46, 0, 43, 68, 0, 0, - 53, 71, 55, 66, 67, 549, 0, 0, 0, 0, - 91, 0, 0, 117, 0, 0, 118, 0, 0, 119, - 0, 0, 120, 0, 83, 0, 589, 0, 0, 0, - 644, 645, 0, 646, 0, 0, 0, 0, 0, 157, - 0, 377, 373, 369, 232, 233, 234, 190, 190, 190, - 190, 0, 0, 544, 545, 543, 544, 547, 509, 202, - 0, 431, 197, 196, 441, 0, 432, 434, 430, 431, - 436, 457, 453, 0, 190, 0, 52, 48, 71, 60, - 0, 0, 70, 0, 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, - 639, 631, 625, 625, 80, 0, 80, 624, 0, 0, - 0, 374, 515, 652, 653, 650, 651, 0, 0, 0, - 0, 0, 0, 0, 410, 24, 405, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 562, - 47, 69, 0, 54, 57, 72, 552, 95, 0, 86, - 99, 0, 121, 0, 122, 123, 132, 0, 124, 125, - 0, 126, 0, 0, 173, 626, 627, 0, 628, 0, - 630, 27, 0, 640, 0, 0, 372, 0, 0, 0, - 190, 546, 548, 190, 509, 509, 508, 203, 190, 435, - 0, 433, 437, 188, 186, 185, 187, 458, 0, 190, - 452, 0, 64, 56, 0, 0, 102, 103, 104, 105, - 85, 85, 85, 85, 138, 0, 146, 142, 151, 152, - 0, 80, 0, 0, 529, 373, 0, 0, 664, 665, - 663, 0, 0, 0, 409, 512, 510, 511, 0, 0, - 0, 454, 0, 0, 63, 97, 0, 0, 0, 0, - 127, 128, 129, 130, 0, 0, 0, 147, 629, 638, + 0, 445, 446, 0, 0, 0, 0, 0, 462, 0, + 0, 191, 419, 420, 481, 0, 0, 487, 0, 0, + 492, 0, 0, 44, 58, 0, 45, 49, 0, 502, + 497, 506, 0, 0, 0, 0, 599, 595, 639, 0, + 0, 0, 0, 0, 0, 0, 0, 644, 156, 159, + 169, 0, 172, 0, 362, 346, 361, 0, 346, 358, + 354, 353, 0, 0, 375, 376, 371, 0, 363, 367, + 0, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 0, 0, 0, 387, 408, + 0, 0, 545, 0, 545, 0, 515, 0, 0, 0, + 0, 0, 199, 198, 190, 190, 0, 396, 0, 0, + 431, 0, 431, 457, 0, 449, 0, 0, 0, 0, + 0, 190, 0, 190, 0, 190, 0, 190, 48, 0, + 59, 0, 0, 556, 557, 558, 559, 0, 174, 100, + 133, 136, 144, 148, 98, 592, 82, 88, 89, 93, + 0, 85, 0, 92, 85, 0, 85, 0, 85, 0, + 85, 0, 85, 84, 0, 590, 575, 600, 630, 529, + 649, 658, 0, 654, 654, 0, 80, 0, 653, 518, + 373, 673, 0, 81, 674, 0, 0, 167, 170, 347, + 359, 344, 355, 0, 384, 0, 368, 365, 0, 0, + 0, 27, 0, 0, 0, 0, 0, 536, 0, 539, + 386, 542, 543, 399, 398, 0, 423, 0, 0, 0, + 0, 0, 27, 0, 463, 0, 560, 0, 0, 566, + 0, 569, 0, 572, 0, 46, 0, 43, 68, 0, + 0, 53, 71, 55, 66, 67, 551, 0, 0, 0, + 0, 91, 0, 0, 117, 0, 0, 118, 0, 0, + 119, 0, 0, 120, 0, 83, 0, 591, 0, 0, + 0, 655, 656, 0, 657, 0, 0, 0, 0, 0, + 676, 678, 157, 0, 377, 373, 369, 232, 233, 234, + 190, 190, 190, 190, 0, 0, 545, 190, 190, 544, + 545, 549, 510, 202, 0, 431, 197, 196, 190, 442, + 0, 190, 190, 430, 431, 437, 458, 454, 0, 190, + 190, 563, 567, 570, 573, 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, 647, + 636, 630, 630, 80, 0, 80, 629, 0, 0, 0, + 374, 516, 666, 667, 664, 665, 0, 0, 0, 0, + 0, 0, 0, 0, 410, 24, 405, 0, 547, 546, + 0, 0, 0, 0, 0, 435, 0, 0, 432, 434, + 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, + 631, 632, 0, 633, 0, 635, 27, 0, 648, 0, + 0, 0, 677, 372, 0, 0, 0, 190, 548, 550, + 190, 510, 510, 509, 203, 190, 436, 0, 190, 438, + 188, 186, 185, 187, 459, 0, 190, 453, 0, 564, + 64, 56, 0, 554, 0, 102, 103, 104, 105, 85, + 85, 85, 85, 138, 0, 146, 142, 151, 152, 0, + 80, 0, 0, 530, 373, 0, 0, 681, 682, 680, + 0, 0, 0, 409, 513, 511, 512, 0, 0, 433, + 0, 455, 0, 0, 63, 97, 0, 0, 0, 0, + 127, 128, 129, 130, 0, 0, 0, 147, 634, 646, 0, 0, 0, 0, 0, 0, 238, 208, 0, 80, - 0, 214, 0, 192, 190, 0, 466, 65, 0, 61, + 0, 214, 0, 192, 190, 0, 467, 65, 0, 61, 106, 107, 108, 109, 110, 111, 85, 139, 0, 143, - 141, 526, 521, 522, 523, 524, 525, 373, 519, 0, - 527, 0, 0, 668, 665, 665, 662, 0, 207, 0, - 212, 0, 0, 213, 0, 0, 0, 0, 465, 62, - 0, 0, 0, 131, 0, 0, 0, 0, 27, 667, - 666, 183, 180, 179, 182, 200, 181, 201, 211, 340, + 141, 527, 522, 523, 524, 525, 526, 373, 520, 0, + 528, 0, 0, 685, 682, 682, 679, 0, 207, 0, + 212, 0, 0, 213, 0, 0, 0, 0, 466, 62, + 0, 0, 0, 131, 0, 0, 0, 0, 27, 684, + 683, 183, 180, 179, 182, 200, 181, 201, 211, 340, 175, 177, 0, 176, 0, 208, 80, 239, 0, 0, - 216, 214, 0, 189, 190, 472, 470, 80, 80, 0, - 112, 113, 114, 115, 140, 0, 518, 194, 654, 190, + 216, 214, 0, 189, 190, 473, 471, 80, 80, 0, + 112, 113, 114, 115, 140, 0, 519, 194, 668, 190, 0, 0, 210, 209, 0, 0, 215, 0, 0, 0, - 467, 469, 0, 0, 135, 0, 0, 0, 0, 0, + 468, 470, 0, 0, 135, 0, 0, 0, 0, 0, 0, 194, 241, 298, 299, 300, 301, 302, 303, 304, 243, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 245, 247, 329, 330, 331, 332, 333, 0, 240, 265, 292, 272, 274, 276, 278, - 0, 271, 288, 184, 80, 473, 373, 116, 190, 520, - 657, 80, 0, 649, 670, 0, 0, 0, 0, 0, + 0, 271, 288, 184, 80, 474, 373, 116, 190, 521, + 671, 80, 0, 663, 687, 0, 0, 0, 0, 0, 0, 235, 0, 0, 0, 0, 0, 0, 0, 237, - 0, 468, 0, 195, 656, 0, 190, 193, 335, 339, + 0, 469, 0, 195, 670, 0, 190, 193, 335, 339, 190, 190, 242, 190, 0, 190, 0, 244, 337, 190, 190, 246, 190, 0, 190, 248, 190, 190, 266, 190, 190, 190, 293, 190, 236, 190, 273, 190, 190, 275, - 190, 277, 190, 190, 279, 190, 289, 190, 471, 0, + 190, 277, 190, 190, 279, 190, 289, 190, 472, 0, 0, 249, 256, 0, 253, 0, 0, 255, 0, 257, 264, 0, 261, 0, 0, 263, 267, 270, 0, 268, 294, 297, 0, 295, 280, 0, 282, 283, 284, 0, - 286, 287, 290, 291, 654, 178, 190, 190, 0, 190, - 0, 190, 190, 0, 190, 190, 190, 190, 190, 655, + 286, 287, 290, 291, 668, 178, 190, 190, 0, 190, + 0, 190, 190, 0, 190, 190, 190, 190, 190, 669, 252, 0, 250, 0, 254, 338, 260, 0, 258, 336, 262, 269, 296, 281, 285, 190, 0, 190, 251, 334, 259 @@ -1218,79 +1234,81 @@ static const yytype_uint16 yydefact[] = /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -1145, -1145, -1145, -206, -222, -184, -1145, -98, -180, 320, - -1145, -1145, -1145, -1145, -1145, -1145, -217, -325, -571, -33, - -675, -564, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -507, - -203, -1145, -1145, -1145, -794, -1145, -1145, -193, -39, 1855, - 1023, -42, -1145, -668, -517, -563, -1145, -1145, -107, -1145, - -1145, -103, -1145, -1145, -1145, -108, -252, -1145, -1145, -741, - -1145, -1145, -1145, -1145, -1145, -684, -1145, -1145, -1145, -1145, - -608, -1145, -1145, -1145, 0, -1145, -1145, -1145, -1145, -1145, - 194, -1145, -1145, -452, -1145, -1145, -685, -1145, -1145, -872, - -1145, -1145, -1145, -1145, -892, 1299, -342, -1144, -477, -1145, - -1145, -1145, -878, -966, 73, -1145, -426, -1145, -1145, -430, - -270, 167, -1145, -1145, -496, -915, -1145, -386, -904, -702, - -1145, -793, -529, -1145, -1145, -1145, -1145, -533, -1145, -1145, - -1145, -1145, -555, -523, -1145, -609, -1145, -1090, -1145, -367, - -1145, 736, -387, -151, 544, -391, 62, -45, -315, 151, - -1145, -1145, -1145, 242, -1145, -56, -1145, -145, -1145, -1145, - -1145, -1145, -1145, -1145, -791, -1145, -1145, -1145, -1145, 627, - 629, 633, 635, -232, 467, -1145, -1145, -105, 58, -1145, - -1145, -1145, -1145, -1145, -611, -1145, -1145, -1145, 3, -1145, - 593, -47, -1145, -1145, -1145, 637, -1145, -1145, -1145, -550, - -1145, -1145, -1145, 558, 572, 198, -148, 4, 323, -1145, - -1145, -1145, -1145, -1145, -1145, -1145, -344, -756, -855, -1145, - -1145, 647, 652, -1145, 245, -1145, -375, -1145, -1145, -1145, - -182, -1145, 660, -1145, -158, -1145, 661, -1145, -166, -1145, - 663, -1145, -170, -1145, -1145, 413, -1145, -1145, -1145, -1145, - -1145, 852, -321, -1145, -1145, -526, -1145, -1145, -692, -1145, - -1145, -1145, -774, -1145, -1145, 667, -1145, -1145, 603, -1145, - 605, -1145, -1145, 232, -569, 235, 237, 238, 673, -1145, - -1145, -1145, -1145, -1145, 676, -1145, -1145, -1145, -1145, 681, - -1145, -1145, 682, -1145, -1145, 684, -1145, -1145, 685, -178, - -322, 118, -1145, -1145, -1145, -1145, -1145, -1145, -1145, -1145, - -1145, -1145, 813, -219, -1145, -104, 405, -1145, 236, -1145, - -1145, -1145, -768, -1145, -1145, -34, 815, -1145, -1017, -515, - -1145, -916, 820, -1145, -1145, -1145, -424, -1145, -223 + -1187, -1187, -1187, -219, -226, -180, -1187, -126, -132, 296, + -1187, -1187, -1187, -1187, -1187, -1187, -223, -334, -589, -38, + -715, -585, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -528, + -245, -1187, -1187, -1187, -831, -1187, -1187, -238, -41, 1769, + 915, -44, -1187, -707, -567, -577, -1187, -1187, -147, -1187, + -1187, -144, -1187, -1187, -1187, -142, -298, -1187, -1187, -741, + -1187, -1187, -1187, -1187, -1187, -708, -1187, -1187, -1187, -1187, + -553, -1187, -1187, -1187, 0, -1187, -1187, -1187, -1187, -1187, + 144, -1187, -1187, -470, -1187, -1187, -698, -1187, -1187, -819, + -1187, -1187, -1187, -1187, -908, 1902, -408, -1186, -531, -1187, + -1187, -1187, -904, -1002, -40, -1187, -483, -1187, -1187, -484, + -278, 133, -1187, -1187, -513, -943, -1187, -440, -939, -726, + -1187, -959, -581, -1187, -1187, -1187, -1187, -593, -1187, -1187, + -1187, -1187, -641, -572, -1187, -639, -1187, -680, -1187, -427, + -1187, 715, -397, -162, 522, -395, 52, -184, -308, 117, + -1187, -1187, -1187, 197, -1187, -92, -1187, -149, -1187, -1187, + -1187, -1187, -1187, -1187, -804, -1187, -1187, -1187, -1187, 609, + 610, 612, 613, -246, 582, -1187, -1187, -93, 88, -1187, + -1187, -1187, -1187, -1187, -529, -1187, -1187, -1187, 2, -1187, + 454, -42, -1187, -1187, -1187, 624, -1187, -1187, -1187, -575, + -1187, -1187, -1187, 559, 560, 291, -191, 7, 293, -1187, + -1187, -1187, -1187, -1187, -1187, -1187, -356, -769, -883, -1187, + -1187, 633, 636, -1187, 207, -1187, -433, -1187, -1187, -1187, + -179, -1187, 641, -1187, -148, -1187, 647, -1187, -160, -1187, + 648, -1187, -158, -1187, -1187, 387, -1187, -1187, -1187, -1187, + -1187, 488, -325, -1187, -1187, -360, -1187, -1187, -729, -1187, + -1187, -1187, -774, -1187, -1187, 651, -1187, -1187, 589, -1187, + 592, -1187, -1187, 199, -558, 209, 211, 218, 676, -1187, + -1187, -1187, -1187, -1187, 679, -1187, -1187, -1187, -1187, 684, + -1187, -1187, 687, -1187, -1187, 689, -1187, -1187, 697, -168, + -303, 119, -1187, -1187, -1187, -1187, -1187, -1187, -1187, -1187, + -1187, -1187, 827, -1187, 511, -233, -1187, -107, -203, -1187, + -1187, -48, -1187, 43, -1187, -1187, -1187, -785, -1187, -1187, + -1187, 515, -17, 839, -1187, -1187, 518, -1061, -525, -1187, + -923, 850, -1187, -1187, -1187, -77, -1187, -416, -1187, -232 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 37, 38, 39, 222, 585, 224, 841, 225, 821, - 226, 227, 391, 392, 228, 328, 229, 230, 851, 555, - 474, 556, 475, 658, 847, 557, 770, 923, 558, 771, - 850, 983, 984, 1058, 772, 773, 774, 852, 108, 208, - 361, 430, 879, 574, 712, 780, 675, 676, 677, 678, - 679, 680, 681, 862, 985, 682, 683, 684, 867, 685, - 686, 871, 995, 1068, 1145, 687, 1036, 688, 874, 997, - 689, 690, 877, 1000, 460, 331, 41, 133, 232, 399, - 400, 401, 580, 402, 403, 582, 692, 693, 1119, 1261, - 1121, 1122, 977, 978, 834, 362, 634, 1123, 1166, 835, - 635, 1124, 830, 968, 422, 423, 1088, 424, 425, 1093, - 426, 614, 615, 616, 817, 1047, 1049, 1051, 1048, 1128, - 1212, 1262, 1271, 1213, 1278, 1220, 1286, 1291, 1221, 1296, - 1244, 1282, 1214, 1263, 1264, 1272, 1273, 1265, 1266, 1126, - 42, 239, 333, 503, 44, 334, 240, 135, 234, 507, - 235, 413, 589, 407, 408, 586, 584, 241, 242, 417, - 418, 599, 511, 595, 806, 596, 812, 46, 47, 48, - 49, 50, 51, 427, 137, 52, 53, 243, 409, 527, - 55, 140, 258, 442, 428, 429, 619, 822, 244, 57, - 142, 196, 283, 284, 463, 58, 59, 260, 261, 748, - 262, 263, 264, 245, 246, 431, 837, 893, 354, 61, - 145, 269, 270, 453, 449, 917, 701, 643, 842, 979, - 62, 63, 64, 275, 457, 1098, 1138, 1139, 1226, 65, + -1, 37, 38, 39, 228, 606, 230, 866, 231, 844, + 232, 233, 409, 410, 234, 339, 235, 236, 880, 575, + 492, 576, 493, 679, 876, 577, 791, 958, 578, 792, + 879, 1021, 1022, 1098, 793, 794, 795, 881, 108, 208, + 372, 448, 908, 595, 733, 801, 696, 697, 698, 699, + 700, 701, 702, 891, 1024, 703, 704, 705, 896, 706, + 707, 900, 1034, 1108, 1185, 708, 1076, 709, 903, 1036, + 710, 711, 906, 1039, 478, 342, 41, 133, 238, 417, + 418, 419, 601, 420, 421, 603, 713, 714, 1159, 1301, + 1161, 1162, 1014, 1015, 859, 373, 655, 1163, 1206, 860, + 656, 1164, 854, 1005, 440, 441, 1128, 442, 443, 1133, + 444, 635, 636, 637, 840, 1087, 1089, 1091, 1088, 1168, + 1252, 1302, 1311, 1253, 1318, 1260, 1326, 1331, 1261, 1336, + 1284, 1322, 1254, 1303, 1304, 1312, 1313, 1305, 1306, 1166, + 42, 245, 344, 523, 44, 345, 246, 135, 240, 527, + 241, 431, 610, 425, 426, 607, 605, 247, 248, 435, + 436, 620, 531, 616, 827, 617, 835, 46, 47, 48, + 49, 50, 51, 445, 137, 52, 53, 249, 427, 547, + 55, 140, 264, 460, 446, 447, 640, 845, 250, 57, + 142, 196, 289, 290, 481, 58, 59, 266, 267, 769, + 268, 269, 270, 251, 252, 449, 862, 922, 365, 61, + 145, 275, 276, 471, 467, 952, 722, 664, 867, 1016, + 62, 63, 64, 281, 475, 1138, 1178, 1179, 1266, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 203, 79, 303, 304, 477, 305, 306, - 480, 894, 910, 435, 626, 488, 489, 709, 702, 1077, - 1078, 1079, 703, 704, 1005, 80, 81, 82, 247, 83, - 248, 84, 85, 249, 733, 250, 251, 252, 86, 87, - 155, 309, 310, 666, 88, 277, 278, 279, 280, 89, - 288, 289, 90, 293, 294, 91, 298, 299, 92, 93, - 312, 565, 94, 157, 316, 317, 485, 95, 175, 96, - 176, 177, 895, 798, 98, 179, 183, 184, 322, 323, - 884, 885, 705, 706, 99, 570, 896, 101, 897, 1168, - 102, 711, 313, 104, 492, 1009, 1045, 493, 1010 + 76, 77, 78, 203, 79, 309, 310, 495, 311, 312, + 498, 923, 942, 453, 647, 927, 509, 730, 723, 1117, + 1118, 1119, 724, 725, 1044, 80, 81, 82, 253, 83, + 254, 84, 85, 255, 754, 256, 257, 258, 86, 87, + 155, 315, 316, 687, 88, 283, 284, 285, 286, 89, + 294, 295, 90, 299, 300, 91, 304, 305, 92, 93, + 318, 585, 94, 157, 322, 323, 503, 95, 175, 96, + 176, 177, 924, 211, 212, 819, 98, 179, 325, 326, + 505, 327, 184, 333, 334, 913, 914, 726, 727, 99, + 214, 215, 591, 925, 101, 217, 218, 926, 1208, 102, + 732, 319, 104, 512, 830, 831, 1048, 1085, 513, 1049 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -1298,656 +1316,672 @@ static const yytype_int16 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 40, 393, 223, 56, 60, 325, 109, 327, 324, 450, - 257, 960, 276, 110, 111, 501, 112, 406, 113, 500, - 114, 899, 115, 883, 180, 181, 116, 311, 117, 886, - 118, 297, 119, 292, 120, 970, 121, 803, 122, 287, - 123, 863, 697, 888, 253, 578, 889, 674, 124, 274, - 329, 660, 700, 1054, 735, 125, 924, 126, 54, 127, - 483, 128, 45, 129, 1107, 130, 132, 134, 136, 136, - 139, 141, 136, 144, 136, 141, 136, 141, 136, 141, - 136, 141, 154, 156, 254, 178, 178, 178, 456, 769, - 1042, 750, 856, 764, 860, 419, 1003, 860, 864, 1281, - 860, 868, 198, 860, 200, 882, 860, 1056, 1050, 1052, - 394, 419, 832, 438, 7, 2, 15, 833, 875, 1, - 783, 824, 786, 15, 789, 4, 792, 2, 794, 12, - 1134, 1115, 105, 419, 5, 965, 836, 4, 433, 1259, - 296, 10, 1055, 420, 231, 214, 397, 5, 1115, 1274, - 1274, 5, 1279, 1283, 33, 1288, 667, 1293, 1293, 473, - 1297, 33, 238, 5, 832, 19, 484, 24, 441, 833, - 421, 233, 1125, 495, 865, 455, 131, 869, 1346, 1001, - 872, 1008, 494, 233, 405, 673, 421, 987, 1052, 34, - 1024, 31, 32, 591, 26, 282, 335, 301, 29, 1228, - 5, 336, 302, 338, 311, 1117, 340, 341, 421, 667, - 182, 828, 349, 1337, 1041, 1120, 948, 964, 950, 21, - 645, 1342, 1117, 185, 10, 1120, 351, 352, 1147, 1059, - 447, 355, 818, 819, 356, 1347, 671, 672, 1299, 1348, - -619, 360, 694, 36, 988, 364, 860, 990, 860, 259, - 367, 1232, 860, 1149, 907, 370, 273, 908, 844, 698, - 373, 848, 566, 809, 1099, 376, 456, 379, 998, 1256, - 1084, 381, 1170, 1171, 31, 32, 1, 592, 383, 922, - 881, 912, 898, 920, 388, 1060, 1105, 1082, 398, 915, - 628, 414, 927, 412, 134, 598, 929, 5, 236, 5, - 932, 934, 935, 669, 670, 938, 939, 237, 667, 941, - -621, 454, 1071, 452, 134, 19, 1072, 1073, 1074, 1075, - 989, 286, 462, 991, 267, 992, 671, 672, 238, 993, - 300, 301, 17, 1038, 476, 768, 672, 479, 657, 34, - 415, 659, 1061, 1063, 860, 233, 268, 437, 447, 696, - 2, 26, 5, 448, 444, 29, 5, 5, 650, 5, - 4, 667, 498, 461, 499, 281, 667, 1270, 1270, 504, - 1277, 670, 620, 622, 1076, 5, 725, 698, 670, 512, - 1259, 1090, 656, 654, 638, 640, 311, 513, 652, 1129, - 516, -622, 1132, 671, 672, 649, 520, 395, 396, 1231, - 671, 672, 631, -623, 1111, 393, 632, 810, 1112, 1113, - 1114, 533, 621, 623, 5, 308, 1140, 537, 1062, 1064, - 1065, 1066, 321, 500, 639, 641, 393, 1030, 1031, 1032, - 1033, 1336, 447, 718, 1339, 1252, 720, 843, 464, 1341, - 5, 467, 1344, 659, 470, 1267, 1345, 10, 326, 1, - 571, -30, 501, 1289, 575, 216, 579, 581, 1153, 416, - 21, 1366, 106, 107, 236, 291, 1116, 433, 238, 1160, - 1161, 714, 17, 237, 618, 206, 207, 631, 625, 1365, - 7, 632, 271, -59, 36, 1367, 5, 5, -59, -59, - -59, 642, 1141, 1142, 1143, 667, 420, 31, 32, 669, - 670, 238, 583, 1103, 832, 17, 588, 5, 813, 833, - 487, 131, 215, 216, 5, 217, 218, 219, 220, 221, - 314, 315, 671, 672, 26, 768, 633, 1083, 29, 708, - 553, 1111, 554, 178, 491, 1112, 1113, 1114, 396, 432, - 5, 5, 395, 1258, 1258, 1259, 1259, 710, 846, 445, - 446, 659, 849, 220, 221, 1227, 1251, 724, 459, 814, - 815, 816, 5, 1254, 691, 466, 1268, 1259, 469, 691, - 1118, 472, 553, 691, 845, 1130, 473, 405, 138, 482, - 1136, 143, -51, 146, 554, 148, 766, 150, 617, 152, - 593, 594, 624, 1116, 627, 668, 744, 629, 630, 878, - 1215, 637, 1222, 870, 1111, 554, 873, 1046, 1112, 1113, - 1114, 1007, 648, 672, 5, 318, 319, 320, 651, 1259, - 486, 653, 490, 973, 655, 765, 393, 974, 975, 976, - 233, 405, 820, 659, 849, 661, 671, 672, 1292, 1292, - 778, 905, 781, 1016, 1017, 784, 390, 787, 925, 790, - 1230, 793, 131, 215, 795, 921, 217, 218, 219, 768, - 1109, 1110, 799, 945, 946, 802, 1116, 804, 800, 801, - 854, 858, 807, 1111, 1046, 857, 986, 1112, 1113, 1114, - 1115, 215, 811, 5, 217, 218, 219, 220, 221, 766, - 577, 767, 667, 1069, 1236, 668, 669, 670, 768, 1152, - 1007, 1156, 829, 1111, 647, 982, 1131, 1112, 1113, 1114, - 147, 1275, 149, 5, 151, 1294, 153, 1268, 1259, 671, - 672, 673, 1287, 1046, 215, 216, 473, 217, 218, 219, - 1137, 967, 5, 768, 823, 1116, 43, 826, 272, 861, - 721, 667, 866, 1002, 668, 669, 670, 587, 890, 831, - 265, 876, 839, 158, 1117, 159, 994, 642, 996, 160, - 642, 161, 1023, 162, 266, 1116, 971, 659, 671, 672, - 673, 215, 532, 163, 217, 218, 219, 855, 164, 859, - 853, 646, 859, 393, 1224, 859, 165, 166, 859, 167, - 478, 859, 255, 168, 256, 662, 913, 691, 663, 169, - 664, 665, 170, 1, 2, 891, 1057, 171, 172, 3, - 173, 174, 796, 97, 4, 100, 5, 6, 5, 1349, - 103, 1085, 0, 7, 0, 0, 8, 667, 0, 0, - 668, 669, 670, 9, 10, 0, 11, 0, 12, 967, - 0, 659, 0, 13, 699, 14, 949, 0, 15, 0, - 1067, 16, 0, 0, 671, 672, 673, 0, 0, 17, - 5, 0, 18, 0, 19, 20, 21, 22, 0, 667, - 0, 829, 668, 669, 670, 23, 24, 25, 26, 27, - 0, 28, 29, 30, 31, 32, 33, 0, 34, 35, - 36, 0, 0, 0, 0, 0, 671, 672, 673, 215, - 216, 999, 217, 218, 219, 220, 221, 0, 215, 963, - 1004, 217, 218, 219, 220, 221, 967, 0, 767, 1111, - 1144, 0, 0, 1112, 1113, 1114, 1115, 0, 0, 5, - 0, 859, 0, 859, 0, 0, 0, 859, 667, 1020, - 0, 668, 669, 670, 0, 0, 0, 691, 1135, 215, - 216, 0, 217, 218, 219, 220, 221, 0, 0, 767, - 5, 0, 0, 3, 0, 671, 672, 673, 1043, 667, - 5, 6, 668, 669, 670, 0, 0, 0, 829, 667, - 8, 1116, 668, 669, 670, 967, 699, 9, 710, 0, - 0, 0, 0, 0, 0, 0, 671, 672, 673, 14, - 1117, 642, 0, 1081, 0, 16, 671, 672, 673, 1089, - 0, 1091, 0, 1094, 0, 0, 18, 0, 0, 20, - 0, 22, 0, 0, 0, 0, 0, 0, 0, 859, + 40, 335, 56, 411, 109, 336, 229, 60, 468, 338, + 328, 110, 111, 330, 112, 282, 113, 695, 114, 824, + 115, 180, 181, 721, 116, 997, 117, 520, 118, 521, + 119, 929, 120, 915, 121, 424, 122, 317, 123, 298, + 259, 508, 1007, 303, 912, 280, 124, 599, 959, 293, + 681, 917, 45, 125, 918, 126, 1094, 127, 263, 128, + 1147, 129, 892, 130, 132, 134, 136, 136, 139, 141, + 136, 144, 136, 141, 136, 141, 136, 141, 136, 141, + 154, 156, 183, 178, 178, 178, 756, 771, 54, 911, + 501, 474, 790, 785, 1, 893, 260, 1321, 897, 904, + 885, 1, 889, 1042, 340, 889, 1, 198, 889, 200, + 456, 889, 1090, 1092, 889, 412, 242, 1155, 437, 1096, + 5, 15, 1082, 465, 5, 243, 507, 804, 438, 807, + 5, 810, 5, 813, 1174, 815, 287, 437, 437, 856, + 182, 688, 237, 220, 857, 2, 244, 105, 5, 5, + 17, 1155, 719, 244, 5, 4, 1095, 17, 307, 1299, + 33, 415, 2, 432, 491, 329, 131, 1002, 331, 693, + 26, 502, 4, 19, 29, 7, 1386, 26, 324, 324, + 185, 29, 26, 472, 1165, 515, 29, 514, 465, 473, + 12, 1064, 1157, 1092, 439, 288, 5, 1040, 34, 451, + 346, 239, 308, 1268, 182, 347, 983, 349, 985, 15, + 351, 352, 1001, 439, 439, 239, 1047, 719, 239, 423, + 612, 691, 1026, 360, 848, 317, 1157, 459, 24, 718, + 362, 363, 1099, 302, 1339, 366, 841, 842, 367, 861, + 1081, -621, 1187, 692, 693, 371, 279, 666, 33, 375, + 894, 910, 465, 898, 378, 1027, 901, -623, 1029, 381, + 5, 877, 869, 1037, 384, 1189, 832, 1139, 889, 387, + 889, 390, 5, 1296, 889, 392, 586, 10, 474, 265, + 944, 715, 394, 613, 1272, 397, 1210, 1211, 937, 950, + 957, 955, 940, 406, 1111, 314, 649, 416, 1112, 1113, + 1114, 1115, 430, 134, 273, 306, 307, 962, 1160, 619, + 1124, 964, 21, 1145, 1122, 967, 969, 970, 1160, 1307, + 973, 974, 470, 134, 976, 1100, 274, 1329, 31, 32, + -624, 480, 5, 1078, 652, 2, 482, 36, 653, 485, + 5, 688, 488, 494, 5, 4, 497, 789, -625, 688, + 433, 329, 678, 504, 331, 680, 1116, 455, 1101, 1103, + -59, 413, 414, 717, 466, -59, -59, -59, 462, 19, + 694, 889, 106, 107, 479, 292, 692, 693, 518, 21, + 519, 671, 1130, 652, 297, 524, 1151, 653, 641, 643, + 1152, 1153, 1154, 746, 34, 532, 5, 856, 852, 10, + 659, 661, 857, 533, 36, 1169, 536, 5, 1172, 675, + 1028, 670, 540, 1030, 677, 1031, 317, 411, 673, 1032, + 244, 5, 1271, 332, 1151, 1308, 1299, 553, 1152, 1153, + 1154, 242, 1180, 557, 5, 833, 520, 1298, 411, 1299, + 243, 506, 337, 739, 642, 644, 741, 510, 1156, -30, + 31, 32, 1070, 1071, 1072, 1073, 660, 662, 680, 1193, + 1310, 1310, 1292, 1317, 5, 868, 222, 1298, 592, 1299, + 1200, 1201, 596, 521, 600, 602, 131, 221, 222, 434, + 223, 224, 225, 226, 227, 1406, 1156, 690, 691, 735, + 451, 5, 639, 5, 7, 638, 646, 856, 1299, 645, + 688, 648, 857, 5, 650, 651, 206, 207, 658, 663, + 692, 693, 438, 1102, 1104, 1105, 1106, 1123, 573, 669, + 574, 413, 604, 836, 1376, 672, 609, 1379, 674, 1143, + 507, 676, 1381, 221, 10, 1384, 223, 224, 225, 1385, + 511, -51, 682, 574, 5, 789, 654, 414, 729, 837, + 838, 839, 178, 688, 1255, 244, 1262, 1291, 691, 17, + 1158, 320, 321, 875, 1294, 1170, 680, 878, 423, 277, + 1176, 147, 1405, 149, 1086, 151, 745, 153, 1407, 731, + 692, 693, 573, 5, 712, 31, 32, 1181, 1182, 1183, + 712, 491, 688, 787, 712, 689, 690, 691, 870, 1314, + 1314, 689, 1319, 1323, 1086, 1328, 574, 1333, 1333, 907, + 1337, 693, 1151, 226, 227, 765, 1152, 1153, 1154, 692, + 693, 694, 5, 614, 615, 843, 928, 1299, 899, 239, + 423, 902, 1151, 408, 1046, 960, 1152, 1153, 1154, 956, + 1270, 786, 5, 450, 692, 693, 1308, 1299, 1332, 1332, + 1267, 883, 411, 463, 464, 886, 680, 878, 887, 799, + 598, 802, 477, 1377, 805, 1025, 808, 1109, 811, 484, + 814, 1382, 487, 816, 1156, 490, 1055, 1056, 980, 981, + 1276, 820, 1192, 500, 823, 1387, 825, 1196, 789, 1388, + 668, 828, 1171, 138, 1156, 1334, 143, 465, 146, 1315, + 148, 834, 150, 465, 152, 5, 821, 822, 1149, 1150, + 1177, 5, 935, 1327, 688, 43, 278, 689, 690, 691, + 688, 853, 608, 689, 690, 691, 719, 742, 1046, 789, + 909, 720, 719, 919, 1020, 158, 159, 720, 160, 161, + 1010, 692, 693, 694, 1011, 1012, 1013, 692, 693, 694, + 162, 271, 272, 847, 846, 491, 1008, 850, 890, 163, + 552, 895, 164, 667, 789, 1041, 1264, 165, 858, 855, + 905, 5, 864, 166, 167, 496, 663, 168, 261, 663, + 688, 262, 683, 221, 690, 691, 223, 224, 225, 226, + 227, 787, 684, 788, 685, 1033, 1063, 1035, 884, 680, + 888, 686, 169, 888, 882, 170, 888, 692, 693, 888, + 171, 1004, 888, 172, 411, 173, 131, 221, 712, 946, + 223, 224, 225, 174, 1, 2, 920, 97, 221, 222, + 3, 223, 224, 225, 817, 4, 396, 5, 6, 100, + 1097, 452, 454, 400, 7, 457, 458, 8, 403, 1389, + 103, 992, 1125, 0, 9, 10, 0, 11, 476, 12, + 0, 0, 0, 0, 13, 483, 14, 0, 486, 15, + 0, 489, 16, 984, 0, 680, 0, 0, 0, 499, + 17, 0, 0, 18, 0, 19, 20, 21, 22, 0, + 0, 0, 0, 0, 1107, 0, 23, 24, 0, 25, + 26, 27, 853, 28, 29, 30, 31, 32, 33, 0, + 34, 35, 36, 1151, 1086, 0, 5, 1152, 1153, 1154, + 1155, 0, 0, 5, 0, 688, 1004, 0, 689, 690, + 691, 0, 688, 0, 1038, 689, 690, 691, 3, 0, + 0, 1000, 720, 1043, 731, 0, 6, 0, 0, 0, + 0, 0, 692, 693, 694, 8, 0, 0, 0, 692, + 693, 694, 9, 0, 1184, 11, 888, 0, 888, 0, + 0, 0, 888, 0, 1060, 1156, 0, 0, 0, 0, + 16, 465, 712, 0, 0, 0, 0, 0, 0, 5, + 0, 18, 0, 0, 20, 1157, 22, 0, 688, 0, + 0, 689, 690, 691, 1004, 1083, 0, 25, 5, 27, + 719, 28, 0, 30, 0, 0, 853, 688, 0, 35, + 689, 690, 691, 0, 0, 692, 693, 694, 0, 0, + 0, 0, 0, 0, 720, 0, 0, 0, 0, 663, + 0, 1121, 0, 0, 692, 693, 694, 1129, 186, 1131, + 187, 1134, 188, 189, 0, 190, 0, 191, 192, 0, + 193, 194, 195, 197, 195, 199, 195, 201, 202, 888, + 204, 0, 205, 1004, 0, 0, 0, 0, 1146, 0, + 0, 0, 0, 0, 712, 1167, 0, 1167, 0, 0, + 1167, 0, 209, 0, 210, 213, 216, 5, 219, 0, + 0, 0, 853, 0, 0, 0, 688, 0, 0, 689, + 690, 691, 0, 0, 0, 0, 1175, 0, 0, 0, + 0, 1190, 0, 1191, 0, 1380, 0, 712, 0, 0, + 0, 0, 712, 692, 693, 694, 0, 712, 1202, 0, + 0, 0, 0, 1004, 0, 0, 853, 853, 0, 0, + 0, 0, 0, 341, 0, 343, 0, 0, 1265, 0, + 0, 0, 348, 0, 350, 1378, 0, 0, 353, 354, + 0, 0, 0, 1383, 355, 356, 357, 358, 0, 359, + 195, 361, 221, 222, 0, 223, 224, 225, 226, 227, + 364, 0, 788, 0, 0, 368, 369, 0, 370, 712, + 0, 0, 0, 0, 374, 0, 0, 712, 376, 377, + 0, 0, 0, 379, 380, 0, 0, 0, 382, 383, + 0, 0, 0, 5, 0, 0, 388, 0, 0, 0, + 391, 1295, 688, 393, 0, 689, 690, 691, 0, 0, + 395, 0, 398, 399, 401, 402, 404, 1151, 405, 0, + 0, 1152, 1153, 1154, 1155, 0, 0, 5, 0, 692, + 693, 694, 0, 1345, 0, 1348, 688, 0, 0, 689, + 690, 691, 1353, 0, 0, 0, 1175, 1300, 1300, 1309, + 1309, 0, 1316, 1320, 0, 1325, 1300, 1330, 1330, 0, + 1335, 0, 0, 692, 693, 694, 221, 0, 0, 223, + 224, 225, 226, 227, 0, 0, 788, 0, 0, 1156, + 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, + 631, 632, 633, 634, 0, 0, 0, 0, 0, 1157, + 0, 0, 516, 517, 0, 0, 0, 0, 0, 343, + 522, 0, 525, 0, 0, 0, 526, 528, 529, 0, + 530, 621, 622, 623, 624, 625, 626, 627, 628, 629, + 0, 535, 0, 0, 537, 538, 0, 539, 0, 541, + 542, 0, 544, 545, 0, 546, 0, 548, 549, 550, + 0, 0, 364, 0, 0, 0, 0, 555, 556, 0, + 0, 559, 560, 0, 0, 0, 0, 0, 565, 566, + 0, 568, 569, 0, 571, 572, 0, 0, 0, 0, + 0, 0, 3, 0, 582, 583, 584, 0, 0, 5, + 6, 589, 0, 590, 0, 593, 0, 594, 688, 8, + 0, 689, 690, 691, 0, 0, 9, 131, 221, 222, + 0, 223, 224, 225, 226, 227, 221, 222, 14, 223, + 224, 225, 226, 227, 16, 692, 693, 694, 0, 0, + 0, 0, 0, 0, 0, 18, 0, 0, 20, 0, + 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 27, 0, 28, 0, 30, 0, 0, - 1106, 0, 0, 35, 691, 0, 0, 1127, 0, 1127, - 0, 0, 1127, 0, 3, 967, 0, 0, 0, 0, - 0, 0, 6, 0, 829, 0, 0, 0, 131, 215, - 216, 8, 217, 218, 219, 220, 221, 0, 9, 0, - 0, 11, 0, 1150, 0, 1151, 0, 691, 0, 0, - 0, 1340, 691, 0, 447, 0, 16, 691, 0, 0, - 1162, 0, 5, 0, 0, 0, 0, 18, 829, 829, - 20, 667, 22, 0, 668, 669, 670, 0, 0, 0, - 1225, 1338, 25, 698, 27, 0, 28, 0, 30, 1343, - 0, 0, 0, 0, 35, 0, 0, 0, 671, 672, - 673, 600, 601, 602, 603, 604, 605, 606, 607, 608, - 609, 610, 611, 612, 613, 0, 186, 0, 187, 691, - 188, 189, 0, 190, 0, 191, 192, 691, 193, 194, - 195, 197, 195, 199, 195, 201, 202, 5, 204, 0, - 205, 0, 0, 0, 0, 0, 667, 0, 0, 668, - 669, 670, 0, 1255, 434, 436, 1135, 0, 439, 440, - 209, 0, 210, 211, 212, 0, 213, 0, 0, 0, - 0, 458, 0, 671, 672, 673, 0, 0, 465, 0, - 0, 468, 0, 0, 471, 1305, 0, 1308, 0, 0, - 0, 0, 481, 0, 1313, 0, 0, 1260, 1260, 1269, - 1269, 0, 1276, 1280, 0, 1285, 1260, 1290, 1290, 0, - 1295, 0, 0, 0, 0, 330, 0, 332, 0, 0, - 0, 0, 0, 0, 337, 0, 339, 0, 0, 0, - 342, 343, 0, 0, 0, 0, 344, 345, 346, 347, - 0, 348, 195, 350, 0, 0, 0, 0, 0, 0, - 0, 0, 353, 0, 0, 3, 0, 357, 358, 0, - 359, 0, 0, 6, 0, 0, 363, 0, 0, 0, - 365, 366, 8, 0, 0, 368, 369, 0, 0, 9, - 371, 372, 0, 0, 0, 0, 0, 0, 377, 0, - 0, 14, 380, 0, 0, 382, 0, 16, 0, 447, - 0, 384, 385, 386, 0, 387, 0, 5, 18, 0, - 0, 20, 0, 22, 0, 0, 667, 0, 0, 668, - 669, 670, 0, 25, 0, 27, 0, 28, 698, 30, - 447, 0, 880, 699, 0, 35, 0, 0, 5, 0, - 0, 0, 0, 671, 672, 673, 0, 667, 0, 0, - 668, 669, 670, 0, 0, 0, 0, 0, 0, 698, - 0, 0, 0, 0, 699, 600, 601, 602, 603, 604, - 605, 606, 607, 608, 671, 672, 673, 0, 0, 0, - 0, 0, 496, 497, 0, 0, 0, 0, 0, 332, - 502, 0, 505, 0, 0, 0, 506, 508, 509, 0, - 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 515, 0, 0, 517, 518, 0, 519, 0, 521, - 522, 0, 524, 525, 0, 526, 0, 528, 529, 530, - 0, 0, 353, 0, 0, 0, 0, 535, 536, 0, - 0, 539, 540, 0, 0, 0, 0, 0, 545, 546, - 0, 548, 549, 0, 551, 552, 0, 0, 0, 0, - 0, 0, 0, 0, 562, 563, 564, 0, 0, 568, - 0, 569, 0, 572, 0, 573, 1172, 1173, 1174, 1175, - 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, - 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, - 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, - 1206, 1207, 1208, 1209, 1210, 1211, 1216, 1173, 1174, 1175, - 1176, 1177, 1178, 1179, 1217, 1181, 1182, 1183, 1184, 1185, - 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, - 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1218, - 1219, 1207, 1208, 1209, 1210, 1211, 0, 0, 0, 0, - 715, 374, 375, 0, 378, 0, 0, 502, 0, 0, - 502, 0, 506, 0, 722, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 727, 728, 729, - 0, 0, 730, 731, 732, 734, 732, 0, 0, 737, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 746, 747, 749, 747, 0, 751, 0, 752, 0, - 754, 0, 756, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 776, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 777, 0, 779, 0, 0, 782, 0, 785, 0, - 788, 0, 791, 0, 791, 0, 0, 564, 0, 0, - 797, 0, 0, 0, 0, 569, 569, 0, 573, 0, - 0, 0, 805, 0, 0, 0, 0, 808, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 531, 0, 0, - 0, 0, 534, 0, 0, 0, 0, 0, 0, 541, - 542, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1173, 1174, 1175, 1176, 1177, 1178, 1179, 560, 1181, 1182, - 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, - 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, - 1203, 1204, 0, 0, 1207, 1208, 1209, 1210, 1211, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 722, 0, 805, 0, 0, 0, 0, - 0, 0, 0, 903, 0, 0, 732, 0, 0, 732, - 0, 909, 0, 911, 747, 0, 0, 0, 0, 914, - 0, 0, 747, 0, 0, 916, 752, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 791, 0, - 928, 0, 791, 0, 0, 0, 931, 933, 791, 0, - 0, 937, 791, 0, 940, 791, 0, 942, 0, 0, - 943, 0, 0, 0, 0, 797, 797, 947, 0, 573, - 0, 951, 952, 0, 0, 0, 0, 0, 0, 0, - 0, 955, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 742, 743, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 0, 736, 0, 0, 0, 0, 0, 6, + 522, 0, 0, 522, 0, 526, 0, 743, 8, 0, + 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, + 748, 749, 750, 16, 0, 751, 752, 753, 755, 753, + 0, 0, 758, 0, 18, 0, 0, 20, 0, 22, + 0, 0, 0, 0, 767, 768, 770, 768, 0, 772, + 25, 773, 27, 775, 28, 777, 30, 0, 0, 0, + 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 797, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 798, 0, 800, 0, 0, 803, + 0, 806, 0, 809, 0, 812, 0, 812, 0, 0, + 584, 0, 0, 818, 0, 0, 0, 0, 590, 590, + 0, 594, 0, 0, 0, 826, 0, 0, 0, 0, + 829, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, + 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, + 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, + 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, + 1251, 1256, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1257, + 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, + 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, + 1241, 1242, 1243, 1244, 1258, 1259, 1247, 1248, 1249, 1250, + 1251, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 743, 0, + 826, 0, 0, 0, 0, 0, 0, 0, 933, 0, + 0, 753, 0, 0, 0, 753, 0, 941, 0, 943, + 768, 0, 0, 0, 0, 0, 947, 0, 0, 768, + 0, 0, 951, 773, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 812, + 0, 963, 0, 812, 0, 0, 0, 966, 968, 812, + 0, 0, 972, 812, 0, 975, 812, 0, 977, 0, + 0, 978, 0, 0, 0, 0, 818, 818, 982, 0, + 594, 0, 986, 987, 0, 0, 0, 0, 0, 0, + 0, 0, 990, 991, 1213, 1214, 1215, 1216, 1217, 1218, + 1219, 0, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, + 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, + 1239, 1240, 1241, 1242, 1243, 1244, 0, 0, 1247, 1248, + 1249, 1250, 1251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1006, 0, 0, - 1011, 1012, 1013, 0, 0, 0, 0, 909, 909, 0, - 0, 0, 0, 1019, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1022, 0, 0, 0, 0, 1026, - 1027, 1028, 0, 1029, 791, 791, 791, 0, 1034, 0, - 1035, 0, 0, 0, 573, 0, 1040, 0, 805, 0, - 0, 0, 1044, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1045, 0, 0, 0, 0, 1050, + 1051, 1052, 0, 0, 0, 0, 941, 941, 0, 0, + 0, 0, 1058, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1062, 0, 0, 0, 0, 0, 0, + 1066, 1067, 1068, 0, 1069, 812, 812, 812, 0, 1074, + 0, 1075, 0, 0, 0, 594, 0, 1080, 0, 826, + 0, 0, 0, 1084, 0, 291, 0, 296, 0, 301, + 0, 0, 313, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 285, 0, 290, 0, 295, 0, 0, 307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1087, 0, 573, 0, 1092, 0, 0, 0, 1096, 1097, - 0, 0, 0, 1100, 1101, 0, 1102, 0, 0, 791, - 0, 1104, 0, 0, 0, 0, 0, 0, 0, 0, - 805, 0, 0, 0, 0, 1108, 0, 1044, 1044, 0, - 0, 0, 0, 0, 0, 0, 900, 901, 902, 904, + 0, 0, 1127, 0, 594, 0, 1132, 0, 0, 0, + 1136, 1137, 0, 0, 0, 1140, 1141, 0, 1142, 0, + 0, 812, 0, 1144, 0, 0, 0, 0, 0, 0, + 0, 0, 826, 0, 0, 0, 0, 1148, 0, 1084, + 1084, 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, 918, 0, 0, 0, 0, 1087, 573, - 0, 1154, 1155, 0, 1092, 1157, 0, 0, 0, 0, - 1159, 573, 0, 1163, 0, 0, 0, 0, 0, 0, - 1165, 1167, 0, 0, 0, 0, 0, 0, 0, 389, - 0, 0, 0, 0, 0, 0, 404, 0, 410, 411, - 0, 0, 0, 1235, 1165, 1237, 0, 0, 0, 0, - 0, 0, 0, 1238, 443, 0, 0, 0, 0, 451, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1239, 1240, - 0, 0, 0, 0, 0, 0, 0, 1242, 1243, 1245, - 1246, 1247, 1248, 0, 0, 1250, 0, 573, 0, 805, - 0, 0, 0, 0, 573, 0, 0, 0, 0, 1014, - 0, 0, 1015, 0, 0, 0, 0, 1018, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1021, 0, - 0, 0, 514, 0, 0, 0, 1303, 0, 1306, 0, - 0, 0, 0, 523, 0, 1311, 0, 1314, 0, 0, - 0, 0, 1318, 0, 0, 0, 1322, 0, 0, 0, - 1325, 0, 538, 0, 0, 1329, 0, 0, 543, 544, - 0, 0, 547, 0, 0, 550, 0, 0, 0, 0, - 0, 0, 559, 0, 0, 561, 0, 0, 0, 0, - 567, 0, 0, 0, 0, 0, 0, 0, 0, 576, - 0, 0, 0, 1095, 0, 0, 0, 1167, 0, 0, - 1351, 1353, 590, 0, 0, 1357, 597, 0, 0, 0, + 1127, 594, 0, 1194, 1195, 0, 1132, 1197, 0, 0, + 0, 0, 1199, 594, 0, 1203, 0, 0, 0, 0, + 0, 0, 1205, 1207, 407, 0, 0, 0, 0, 0, + 0, 422, 0, 428, 429, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1275, 1205, 1277, 0, 461, + 0, 0, 0, 0, 469, 1278, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 636, 0, 0, 0, 0, 0, 0, 644, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1279, 1280, 0, 0, 0, 0, 0, 0, 0, 1282, + 1283, 1285, 1286, 1287, 1288, 0, 0, 1290, 0, 594, + 0, 826, 0, 0, 0, 0, 594, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 695, 0, 0, 0, 0, 707, 0, 0, 0, 713, - 0, 0, 0, 1158, 0, 716, 0, 717, 0, 0, - 0, 719, 0, 0, 0, 0, 0, 723, 1169, 0, - 0, 0, 0, 0, 726, 0, 0, 0, 0, 0, + 385, 386, 0, 389, 534, 0, 0, 0, 1343, 0, + 1346, 0, 0, 0, 0, 543, 0, 1351, 0, 1354, + 0, 0, 0, 0, 1358, 0, 0, 0, 1362, 0, + 0, 0, 1365, 0, 558, 0, 0, 1369, 0, 0, + 563, 564, 0, 0, 567, 0, 0, 570, 0, 0, + 0, 0, 0, 0, 579, 0, 0, 581, 0, 0, + 0, 0, 587, 0, 588, 0, 0, 0, 0, 0, + 0, 0, 0, 597, 0, 0, 0, 0, 0, 1207, + 0, 0, 1391, 1393, 0, 0, 611, 1397, 0, 0, + 618, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 657, 0, 0, 0, + 0, 0, 0, 665, 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, 736, - 0, 0, 738, 739, 740, 741, 0, 0, 0, 0, - 0, 0, 745, 0, 0, 0, 0, 0, 0, 0, - 0, 753, 0, 755, 0, 757, 758, 759, 760, 761, - 762, 763, 0, 0, 0, 0, 775, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 716, 0, 0, 0, 0, 0, + 728, 0, 0, 0, 734, 0, 0, 0, 551, 0, + 737, 0, 738, 554, 0, 0, 740, 0, 0, 0, + 561, 562, 744, 0, 0, 0, 0, 0, 0, 747, + 0, 0, 0, 0, 0, 0, 0, 0, 580, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1300, 0, 0, 0, 1301, - 1302, 0, 1304, 0, 1307, 0, 0, 0, 1309, 1310, - 0, 1312, 0, 1315, 0, 1316, 1317, 0, 1319, 1320, - 1321, 0, 1323, 0, 1324, 0, 1326, 1327, 825, 1328, - 827, 1330, 1331, 0, 1332, 0, 1333, 0, 0, 0, - 0, 0, 0, 838, 0, 840, 0, 0, 0, 0, + 0, 0, 0, 0, 757, 0, 0, 759, 760, 761, + 762, 0, 0, 0, 0, 0, 0, 766, 0, 0, + 0, 0, 0, 0, 0, 0, 774, 0, 776, 0, + 0, 779, 0, 781, 0, 783, 0, 0, 0, 0, + 0, 796, 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, 1350, 1352, 0, 1354, 0, - 1356, 1358, 0, 1360, 1361, 1362, 1363, 1364, 0, 0, - 0, 0, 0, 887, 0, 0, 0, 0, 0, 0, - 0, 892, 0, 0, 1368, 0, 1370, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 906, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 919, 0, 0, 0, 0, 0, 0, 0, 926, 0, - 0, 0, 0, 0, 0, 0, 0, 930, 0, 0, - 0, 0, 936, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 944, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 953, 0, 0, 0, 0, - 0, 0, 954, 0, 956, 957, 958, 959, 0, 0, - 0, 0, 961, 962, 0, 966, 0, 969, 0, 0, - 972, 0, 980, 981, 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, 849, 0, 851, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 863, 0, + 865, 0, 0, 0, 0, 0, 0, 871, 0, 872, + 0, 873, 0, 874, 0, 0, 763, 764, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 778, 0, 780, 0, 782, 0, 784, + 0, 0, 0, 0, 0, 0, 0, 0, 916, 0, + 0, 0, 0, 0, 0, 0, 921, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 936, 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, - 1025, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1037, 0, 1039, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1070, 0, 0, 0, 0, 1080, 0, 0, 0, - 1086, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 965, 0, 0, 0, 0, 971, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 979, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 988, 0, + 0, 0, 0, 0, 0, 989, 0, 0, 993, 994, + 995, 996, 0, 0, 0, 0, 998, 0, 0, 999, + 0, 1003, 0, 1006, 0, 0, 0, 0, 0, 1009, + 0, 1017, 1018, 1019, 0, 0, 0, 0, 0, 0, + 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 930, 931, 932, 934, 0, 0, 0, 938, + 939, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 945, 0, 0, 948, 949, 0, 0, 0, 0, 0, + 0, 953, 954, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 961, 0, 0, 0, 0, 0, + 0, 0, 0, 1065, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1077, 0, + 1079, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1093, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1110, 0, 0, 0, 0, + 1120, 0, 0, 0, 1126, 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, - 1133, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1146, 0, 1148, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1053, + 0, 0, 1054, 0, 1173, 0, 0, 1057, 0, 0, + 1059, 0, 0, 0, 1186, 0, 1188, 0, 1061, 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, - 1164, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1223, 0, 0, 0, 0, 0, 0, - 0, 1229, 0, 1233, 1234, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1204, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1263, 0, 0, + 0, 0, 0, 0, 0, 1269, 0, 1273, 1274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1135, 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, 1241, 0, 0, - 0, 0, 0, 0, 0, 1249, 0, 0, 0, 0, + 0, 1281, 0, 0, 0, 0, 0, 0, 0, 1289, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1257, 0, 0, 0, 0, 0, 0, 0, 1284, - 0, 0, 0, 0, 0, 0, 0, 1298, 0, 0, + 0, 0, 0, 0, 0, 1297, 0, 0, 0, 0, + 0, 0, 0, 1324, 0, 0, 0, 0, 0, 0, + 0, 1338, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1209, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1374, 1375, 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, 1334, 1335, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1395, + 0, 0, 1399, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1293, 0, 0, 0, 0, 1409, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1340, 0, + 0, 0, 1341, 1342, 0, 1344, 0, 1347, 0, 0, + 0, 1349, 1350, 0, 1352, 0, 1355, 0, 1356, 1357, + 0, 1359, 1360, 1361, 0, 1363, 0, 1364, 0, 1366, + 1367, 0, 1368, 0, 1370, 1371, 0, 1372, 0, 1373, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1355, 0, 0, 1359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1369 + 0, 0, 0, 0, 0, 0, 0, 0, 1390, 1392, + 0, 1394, 0, 1396, 1398, 0, 1400, 1401, 1402, 1403, + 1404, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1408, 0, 1410 }; static const yytype_int16 yycheck[] = { - 0, 326, 186, 0, 0, 222, 45, 229, 214, 353, - 190, 903, 194, 52, 53, 406, 55, 332, 57, 406, - 59, 812, 61, 797, 128, 129, 65, 205, 67, 797, - 69, 201, 71, 199, 73, 913, 75, 705, 77, 197, - 79, 782, 568, 799, 189, 497, 802, 564, 87, 194, - 230, 558, 569, 1019, 623, 94, 850, 96, 0, 98, - 382, 100, 0, 102, 1081, 104, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 189, 127, 128, 129, 358, 660, - 1006, 641, 777, 657, 779, 6, 951, 782, 782, 1243, - 785, 785, 149, 788, 151, 797, 791, 1022, 1012, 1013, - 327, 6, 7, 345, 24, 5, 49, 12, 793, 4, - 683, 732, 685, 49, 687, 15, 689, 5, 691, 39, - 1096, 14, 0, 6, 17, 909, 747, 15, 48, 22, - 73, 35, 1020, 16, 186, 184, 330, 17, 14, 1239, - 1240, 17, 1242, 1243, 87, 1245, 26, 1247, 1248, 376, - 1250, 87, 56, 17, 7, 65, 383, 77, 348, 12, - 81, 61, 1087, 390, 782, 357, 146, 785, 1322, 947, - 788, 955, 388, 61, 62, 55, 81, 928, 1092, 89, - 984, 85, 86, 508, 79, 195, 235, 51, 83, 1165, - 17, 240, 202, 242, 382, 88, 245, 246, 81, 26, - 40, 737, 259, 1303, 1005, 1087, 884, 909, 886, 67, - 535, 1311, 88, 162, 35, 1097, 265, 266, 1106, 1023, - 9, 270, 728, 729, 273, 1325, 53, 54, 1255, 1329, - 162, 280, 564, 91, 928, 284, 931, 931, 933, 191, - 289, 1167, 937, 1108, 823, 294, 194, 826, 754, 38, - 299, 768, 484, 715, 1058, 304, 536, 306, 943, 1235, - 1044, 310, 1150, 1151, 85, 86, 4, 509, 317, 850, - 797, 831, 808, 847, 323, 1026, 1077, 1043, 330, 839, - 522, 336, 855, 335, 336, 512, 859, 17, 19, 17, - 863, 864, 865, 30, 31, 868, 869, 28, 26, 872, - 162, 356, 7, 355, 356, 65, 11, 12, 13, 14, - 928, 71, 364, 931, 3, 933, 53, 54, 56, 937, - 50, 51, 60, 1001, 376, 660, 54, 379, 555, 89, - 337, 558, 1026, 1027, 1029, 61, 25, 344, 9, 566, - 5, 79, 17, 353, 350, 83, 17, 17, 540, 17, - 15, 26, 401, 363, 403, 23, 26, 1239, 1240, 408, - 1242, 31, 517, 518, 69, 17, 598, 38, 31, 418, - 22, 1049, 552, 549, 529, 530, 564, 426, 546, 1091, - 429, 162, 1094, 53, 54, 540, 435, 32, 33, 1167, - 53, 54, 7, 162, 7, 730, 11, 722, 11, 12, - 13, 450, 517, 518, 17, 64, 1100, 456, 1026, 1027, - 1028, 1029, 41, 810, 529, 530, 751, 990, 991, 992, - 993, 1303, 9, 584, 1306, 1226, 587, 752, 365, 1311, - 17, 368, 1314, 660, 371, 1238, 1318, 35, 149, 4, - 489, 149, 843, 1246, 493, 148, 498, 499, 1126, 57, - 67, 1353, 158, 159, 19, 72, 69, 48, 56, 1137, - 1138, 575, 60, 28, 516, 160, 161, 7, 520, 1351, - 24, 11, 70, 155, 91, 1357, 17, 17, 160, 161, - 162, 533, 1100, 1101, 1102, 26, 16, 85, 86, 30, - 31, 56, 502, 1066, 7, 60, 506, 17, 725, 12, - 25, 146, 147, 148, 17, 150, 151, 152, 153, 154, - 74, 75, 53, 54, 79, 850, 526, 1044, 83, 571, - 154, 7, 156, 575, 47, 11, 12, 13, 33, 341, - 17, 17, 32, 20, 20, 22, 22, 45, 765, 351, - 352, 768, 769, 153, 154, 1163, 1224, 596, 360, 150, - 151, 152, 17, 1231, 564, 367, 21, 22, 370, 569, - 1087, 373, 154, 573, 756, 1092, 793, 62, 111, 381, - 1097, 114, 154, 116, 156, 118, 155, 120, 515, 122, - 58, 59, 519, 69, 521, 29, 635, 524, 525, 146, - 1155, 528, 1157, 787, 7, 156, 790, 8, 11, 12, - 13, 955, 539, 54, 17, 210, 211, 212, 545, 22, - 384, 548, 386, 7, 551, 658, 951, 11, 12, 13, - 61, 62, 730, 850, 851, 562, 53, 54, 1247, 1248, - 679, 821, 681, 964, 965, 684, 326, 686, 851, 688, - 1167, 690, 146, 147, 693, 848, 150, 151, 152, 984, - 1084, 1085, 701, 882, 883, 704, 69, 706, 702, 703, - 777, 779, 711, 7, 8, 778, 928, 11, 12, 13, - 14, 147, 724, 17, 150, 151, 152, 153, 154, 155, - 496, 157, 26, 1035, 1171, 29, 30, 31, 1023, 1125, - 1044, 1131, 744, 7, 537, 922, 1092, 11, 12, 13, - 117, 1240, 119, 17, 121, 1248, 123, 21, 22, 53, - 54, 55, 1245, 8, 147, 148, 943, 150, 151, 152, - 1097, 911, 17, 1058, 731, 69, 0, 734, 194, 781, - 589, 26, 784, 949, 29, 30, 31, 505, 804, 746, - 192, 793, 749, 126, 88, 126, 940, 799, 942, 126, - 802, 126, 984, 126, 192, 69, 914, 984, 53, 54, - 55, 147, 449, 126, 150, 151, 152, 777, 126, 779, - 776, 536, 782, 1108, 1159, 785, 126, 126, 788, 126, - 377, 791, 189, 126, 189, 563, 835, 797, 563, 126, - 563, 563, 126, 4, 5, 805, 1023, 126, 126, 10, - 126, 126, 694, 0, 15, 0, 17, 18, 17, 1334, - 0, 1044, -1, 24, -1, -1, 27, 26, -1, -1, - 29, 30, 31, 34, 35, -1, 37, -1, 39, 1019, - -1, 1058, -1, 44, 43, 46, 885, -1, 49, -1, - 1034, 52, -1, -1, 53, 54, 55, -1, -1, 60, - 17, -1, 63, -1, 65, 66, 67, 68, -1, 26, - -1, 913, 29, 30, 31, 76, 77, 78, 79, 80, - -1, 82, 83, 84, 85, 86, 87, -1, 89, 90, - 91, -1, -1, -1, -1, -1, 53, 54, 55, 147, - 148, 943, 150, 151, 152, 153, 154, -1, 147, 909, - 952, 150, 151, 152, 153, 154, 1096, -1, 157, 7, - 1104, -1, -1, 11, 12, 13, 14, -1, -1, 17, - -1, 931, -1, 933, -1, -1, -1, 937, 26, 978, - -1, 29, 30, 31, -1, -1, -1, 947, 36, 147, - 148, -1, 150, 151, 152, 153, 154, -1, -1, 157, - 17, -1, -1, 10, -1, 53, 54, 55, 1007, 26, - 17, 18, 29, 30, 31, -1, -1, -1, 1020, 26, - 27, 69, 29, 30, 31, 1165, 43, 34, 45, -1, - -1, -1, -1, -1, -1, -1, 53, 54, 55, 46, - 88, 1043, -1, 1042, -1, 52, 53, 54, 55, 1048, - -1, 1050, -1, 1052, -1, -1, 63, -1, -1, 66, - -1, 68, -1, -1, -1, -1, -1, -1, -1, 1029, - -1, 78, -1, 80, -1, 82, -1, 84, -1, -1, - 1079, -1, -1, 90, 1044, -1, -1, 1089, -1, 1091, - -1, -1, 1094, -1, 10, 1235, -1, -1, -1, -1, - -1, -1, 18, -1, 1106, -1, -1, -1, 146, 147, - 148, 27, 150, 151, 152, 153, 154, -1, 34, -1, - -1, 37, -1, 1122, -1, 1124, -1, 1087, -1, -1, - -1, 1308, 1092, -1, 9, -1, 52, 1097, -1, -1, - 1139, -1, 17, -1, -1, -1, -1, 63, 1150, 1151, - 66, 26, 68, -1, 29, 30, 31, -1, -1, -1, - 1162, 1305, 78, 38, 80, -1, 82, -1, 84, 1313, - -1, -1, -1, -1, 90, -1, -1, -1, 53, 54, - 55, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, -1, 133, -1, 135, 1159, - 137, 138, -1, 140, -1, 142, 143, 1167, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 17, 155, -1, - 157, -1, -1, -1, -1, -1, 26, -1, -1, 29, - 30, 31, -1, 1232, 342, 343, 36, -1, 346, 347, - 177, -1, 179, 180, 181, -1, 183, -1, -1, -1, - -1, 359, -1, 53, 54, 55, -1, -1, 366, -1, - -1, 369, -1, -1, 372, 1264, -1, 1266, -1, -1, - -1, -1, 380, -1, 1273, -1, -1, 1237, 1238, 1239, - 1240, -1, 1242, 1243, -1, 1245, 1246, 1247, 1248, -1, - 1250, -1, -1, -1, -1, 232, -1, 234, -1, -1, - -1, -1, -1, -1, 241, -1, 243, -1, -1, -1, - 247, 248, -1, -1, -1, -1, 253, 254, 255, 256, - -1, 258, 259, 260, -1, -1, -1, -1, -1, -1, - -1, -1, 269, -1, -1, 10, -1, 274, 275, -1, - 277, -1, -1, 18, -1, -1, 283, -1, -1, -1, - 287, 288, 27, -1, -1, 292, 293, -1, -1, 34, - 297, 298, -1, -1, -1, -1, -1, -1, 305, -1, - -1, 46, 309, -1, -1, 312, -1, 52, -1, 9, - -1, 318, 319, 320, -1, 322, -1, 17, 63, -1, - -1, 66, -1, 68, -1, -1, 26, -1, -1, 29, - 30, 31, -1, 78, -1, 80, -1, 82, 38, 84, - 9, -1, 42, 43, -1, 90, -1, -1, 17, -1, - -1, -1, -1, 53, 54, 55, -1, 26, -1, -1, - 29, 30, 31, -1, -1, -1, -1, -1, -1, 38, - -1, -1, -1, -1, 43, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 53, 54, 55, -1, -1, -1, - -1, -1, 399, 400, -1, -1, -1, -1, -1, 406, - 407, -1, 409, -1, -1, -1, 413, 414, 415, -1, - 417, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 428, -1, -1, 431, 432, -1, 434, -1, 436, - 437, -1, 439, 440, -1, 442, -1, 444, 445, 446, - -1, -1, 449, -1, -1, -1, -1, 454, 455, -1, - -1, 458, 459, -1, -1, -1, -1, -1, 465, 466, - -1, 468, 469, -1, 471, 472, -1, -1, -1, -1, - -1, -1, -1, -1, 481, 482, 483, -1, -1, 486, - -1, 488, -1, 490, -1, 492, 106, 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, 106, 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, -1, -1, -1, -1, - 577, 302, 303, -1, 305, -1, -1, 584, -1, -1, - 587, -1, 589, -1, 591, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 614, 615, 616, - -1, -1, 619, 620, 621, 622, 623, -1, -1, 626, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 638, 639, 640, 641, -1, 643, -1, 645, -1, - 647, -1, 649, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 666, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 678, -1, 680, -1, -1, 683, -1, 685, -1, - 687, -1, 689, -1, 691, -1, -1, 694, -1, -1, - 697, -1, -1, -1, -1, 702, 703, -1, 705, -1, - -1, -1, 709, -1, -1, -1, -1, 714, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 448, -1, -1, - -1, -1, 453, -1, -1, -1, -1, -1, -1, 460, - 461, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 107, 108, 109, 110, 111, 112, 113, 478, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, -1, -1, 141, 142, 143, 144, 145, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 810, -1, 812, -1, -1, -1, -1, - -1, -1, -1, 820, -1, -1, 823, -1, -1, 826, - -1, 828, -1, 830, 831, -1, -1, -1, -1, 836, - -1, -1, 839, -1, -1, 842, 843, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 855, -1, - 857, -1, 859, -1, -1, -1, 863, 864, 865, -1, - -1, 868, 869, -1, 871, 872, -1, 874, -1, -1, - 877, -1, -1, -1, -1, 882, 883, 884, -1, 886, - -1, 888, 889, -1, -1, -1, -1, -1, -1, -1, - -1, 898, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 633, 634, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 220, 0, 337, 45, 228, 186, 0, 364, 235, + 213, 52, 53, 216, 55, 194, 57, 584, 59, 726, + 61, 128, 129, 590, 65, 933, 67, 424, 69, 424, + 71, 835, 73, 818, 75, 343, 77, 205, 79, 199, + 189, 401, 946, 201, 818, 194, 87, 517, 879, 197, + 578, 820, 0, 94, 823, 96, 1058, 98, 190, 100, + 1121, 102, 803, 104, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 130, 127, 128, 129, 644, 662, 0, 818, + 393, 369, 681, 678, 4, 803, 189, 1283, 806, 814, + 798, 4, 800, 986, 236, 803, 4, 149, 806, 151, + 356, 809, 1051, 1052, 812, 338, 19, 14, 6, 1062, + 17, 49, 1045, 9, 17, 28, 25, 704, 16, 706, + 17, 708, 17, 710, 1136, 712, 23, 6, 6, 7, + 40, 26, 186, 184, 12, 5, 56, 0, 17, 17, + 60, 14, 38, 56, 17, 15, 1060, 60, 51, 22, + 88, 341, 5, 347, 387, 213, 147, 941, 216, 54, + 80, 394, 15, 65, 84, 24, 1362, 80, 78, 78, + 163, 84, 80, 367, 1127, 408, 84, 406, 9, 368, + 39, 1022, 89, 1132, 82, 195, 17, 982, 90, 48, + 241, 61, 202, 1205, 40, 246, 913, 248, 915, 49, + 251, 252, 941, 82, 82, 61, 990, 38, 61, 62, + 528, 31, 963, 265, 753, 393, 89, 359, 77, 589, + 271, 272, 1063, 73, 1295, 276, 749, 750, 279, 768, + 1044, 163, 1146, 53, 54, 286, 194, 555, 88, 290, + 803, 818, 9, 806, 295, 963, 809, 163, 966, 300, + 17, 789, 775, 978, 305, 1148, 736, 1098, 966, 310, + 968, 312, 17, 1275, 972, 316, 502, 35, 556, 191, + 855, 584, 323, 529, 1207, 326, 1190, 1191, 846, 864, + 879, 876, 850, 334, 7, 64, 542, 341, 11, 12, + 13, 14, 346, 347, 3, 50, 51, 884, 1127, 532, + 1084, 888, 67, 1117, 1083, 892, 893, 894, 1137, 1278, + 897, 898, 366, 367, 901, 1066, 25, 1286, 86, 87, + 163, 375, 17, 1040, 7, 5, 376, 92, 11, 379, + 17, 26, 382, 387, 17, 15, 390, 681, 163, 26, + 348, 399, 575, 397, 402, 578, 69, 355, 1066, 1067, + 156, 32, 33, 586, 364, 161, 162, 163, 361, 65, + 55, 1069, 159, 160, 374, 71, 53, 54, 419, 67, + 421, 560, 1089, 7, 72, 426, 7, 11, 537, 538, + 11, 12, 13, 619, 90, 436, 17, 7, 758, 35, + 549, 550, 12, 444, 92, 1131, 447, 17, 1134, 569, + 963, 560, 453, 966, 572, 968, 584, 751, 566, 972, + 56, 17, 1207, 41, 7, 21, 22, 468, 11, 12, + 13, 19, 1140, 474, 17, 743, 833, 20, 772, 22, + 28, 398, 150, 605, 537, 538, 608, 404, 69, 150, + 86, 87, 1029, 1030, 1031, 1032, 549, 550, 681, 1166, + 1279, 1280, 1266, 1282, 17, 773, 149, 20, 509, 22, + 1177, 1178, 513, 868, 518, 519, 147, 148, 149, 57, + 151, 152, 153, 154, 155, 1393, 69, 30, 31, 596, + 48, 17, 536, 17, 24, 535, 540, 7, 22, 539, + 26, 541, 12, 17, 544, 545, 161, 162, 548, 553, + 53, 54, 16, 1066, 1067, 1068, 1069, 1084, 155, 559, + 157, 32, 522, 746, 1343, 565, 526, 1346, 568, 1106, + 25, 571, 1351, 148, 35, 1354, 151, 152, 153, 1358, + 47, 155, 582, 157, 17, 879, 546, 33, 592, 151, + 152, 153, 596, 26, 1195, 56, 1197, 1264, 31, 60, + 1127, 74, 75, 786, 1271, 1132, 789, 790, 62, 70, + 1137, 117, 1391, 119, 8, 121, 617, 123, 1397, 45, + 53, 54, 155, 17, 584, 86, 87, 1140, 1141, 1142, + 590, 814, 26, 156, 594, 29, 30, 31, 777, 1279, + 1280, 29, 1282, 1283, 8, 1285, 157, 1287, 1288, 147, + 1290, 54, 7, 154, 155, 656, 11, 12, 13, 53, + 54, 55, 17, 58, 59, 751, 829, 22, 808, 61, + 62, 811, 7, 337, 990, 880, 11, 12, 13, 877, + 1207, 679, 17, 352, 53, 54, 21, 22, 1287, 1288, + 1203, 798, 986, 362, 363, 799, 879, 880, 800, 700, + 516, 702, 371, 1343, 705, 963, 707, 1075, 709, 378, + 711, 1351, 381, 714, 69, 384, 1001, 1002, 911, 912, + 1211, 722, 1165, 392, 725, 1365, 727, 1171, 1022, 1369, + 557, 732, 1132, 111, 69, 1288, 114, 9, 116, 1280, + 118, 745, 120, 9, 122, 17, 723, 724, 1124, 1125, + 1137, 17, 844, 1285, 26, 0, 194, 29, 30, 31, + 26, 765, 525, 29, 30, 31, 38, 610, 1084, 1063, + 42, 43, 38, 825, 957, 126, 126, 43, 126, 126, + 7, 53, 54, 55, 11, 12, 13, 53, 54, 55, + 126, 192, 192, 753, 752, 978, 947, 755, 802, 126, + 467, 805, 126, 556, 1098, 984, 1199, 126, 768, 767, + 814, 17, 770, 126, 126, 388, 820, 126, 189, 823, + 26, 189, 583, 148, 30, 31, 151, 152, 153, 154, + 155, 156, 583, 158, 583, 975, 1022, 977, 798, 1022, + 800, 583, 126, 803, 797, 126, 806, 53, 54, 809, + 126, 943, 812, 126, 1148, 126, 147, 148, 818, 860, + 151, 152, 153, 126, 4, 5, 826, 0, 148, 149, + 10, 151, 152, 153, 715, 15, 325, 17, 18, 0, + 1063, 353, 354, 328, 24, 357, 358, 27, 330, 1374, + 0, 928, 1084, -1, 34, 35, -1, 37, 370, 39, + -1, -1, -1, -1, 44, 377, 46, -1, 380, 49, + -1, 383, 52, 914, -1, 1098, -1, -1, -1, 391, + 60, -1, -1, 63, -1, 65, 66, 67, 68, -1, + -1, -1, -1, -1, 1074, -1, 76, 77, -1, 79, + 80, 81, 946, 83, 84, 85, 86, 87, 88, -1, + 90, 91, 92, 7, 8, -1, 17, 11, 12, 13, + 14, -1, -1, 17, -1, 26, 1058, -1, 29, 30, + 31, -1, 26, -1, 978, 29, 30, 31, 10, -1, + -1, 941, 43, 987, 45, -1, 18, -1, -1, -1, + -1, -1, 53, 54, 55, 27, -1, -1, -1, 53, + 54, 55, 34, -1, 1144, 37, 966, -1, 968, -1, + -1, -1, 972, -1, 1015, 69, -1, -1, -1, -1, + 52, 9, 982, -1, -1, -1, -1, -1, -1, 17, + -1, 63, -1, -1, 66, 89, 68, -1, 26, -1, + -1, 29, 30, 31, 1136, 1046, -1, 79, 17, 81, + 38, 83, -1, 85, -1, -1, 1060, 26, -1, 91, + 29, 30, 31, -1, -1, 53, 54, 55, -1, -1, + -1, -1, -1, -1, 43, -1, -1, -1, -1, 1083, + -1, 1082, -1, -1, 53, 54, 55, 1088, 133, 1090, + 135, 1092, 137, 138, -1, 140, -1, 142, 143, -1, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 1069, + 155, -1, 157, 1205, -1, -1, -1, -1, 1119, -1, + -1, -1, -1, -1, 1084, 1129, -1, 1131, -1, -1, + 1134, -1, 177, -1, 179, 180, 181, 17, 183, -1, + -1, -1, 1146, -1, -1, -1, 26, -1, -1, 29, + 30, 31, -1, -1, -1, -1, 36, -1, -1, -1, + -1, 1162, -1, 1164, -1, 1348, -1, 1127, -1, -1, + -1, -1, 1132, 53, 54, 55, -1, 1137, 1179, -1, + -1, -1, -1, 1275, -1, -1, 1190, 1191, -1, -1, + -1, -1, -1, 238, -1, 240, -1, -1, 1202, -1, + -1, -1, 247, -1, 249, 1345, -1, -1, 253, 254, + -1, -1, -1, 1353, 259, 260, 261, 262, -1, 264, + 265, 266, 148, 149, -1, 151, 152, 153, 154, 155, + 275, -1, 158, -1, -1, 280, 281, -1, 283, 1199, + -1, -1, -1, -1, 289, -1, -1, 1207, 293, 294, + -1, -1, -1, 298, 299, -1, -1, -1, 303, 304, + -1, -1, -1, 17, -1, -1, 311, -1, -1, -1, + 315, 1272, 26, 318, -1, 29, 30, 31, -1, -1, + 325, -1, 327, 328, 329, 330, 331, 7, 333, -1, + -1, 11, 12, 13, 14, -1, -1, 17, -1, 53, + 54, 55, -1, 1304, -1, 1306, 26, -1, -1, 29, + 30, 31, 1313, -1, -1, -1, 36, 1277, 1278, 1279, + 1280, -1, 1282, 1283, -1, 1285, 1286, 1287, 1288, -1, + 1290, -1, -1, 53, 54, 55, 148, -1, -1, 151, + 152, 153, 154, 155, -1, -1, 158, -1, -1, 69, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, + 103, 104, 105, 106, -1, -1, -1, -1, -1, 89, + -1, -1, 417, 418, -1, -1, -1, -1, -1, 424, + 425, -1, 427, -1, -1, -1, 431, 432, 433, -1, + 435, 93, 94, 95, 96, 97, 98, 99, 100, 101, + -1, 446, -1, -1, 449, 450, -1, 452, -1, 454, + 455, -1, 457, 458, -1, 460, -1, 462, 463, 464, + -1, -1, 467, -1, -1, -1, -1, 472, 473, -1, + -1, 476, 477, -1, -1, -1, -1, -1, 483, 484, + -1, 486, 487, -1, 489, 490, -1, -1, -1, -1, + -1, -1, 10, -1, 499, 500, 501, -1, -1, 17, + 18, 506, -1, 508, -1, 510, -1, 512, 26, 27, + -1, 29, 30, 31, -1, -1, 34, 147, 148, 149, + -1, 151, 152, 153, 154, 155, 148, 149, 46, 151, + 152, 153, 154, 155, 52, 53, 54, 55, -1, -1, + -1, -1, -1, -1, -1, 63, -1, -1, 66, -1, + 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 79, -1, 81, -1, 83, -1, 85, -1, -1, + -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, -1, 598, -1, -1, -1, -1, -1, 18, + 605, -1, -1, 608, -1, 610, -1, 612, 27, -1, + -1, -1, -1, -1, -1, 34, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 46, -1, -1, + 635, 636, 637, 52, -1, 640, 641, 642, 643, 644, + -1, -1, 647, -1, 63, -1, -1, 66, -1, 68, + -1, -1, -1, -1, 659, 660, 661, 662, -1, 664, + 79, 666, 81, 668, 83, 670, 85, -1, -1, -1, + -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 687, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 699, -1, 701, -1, -1, 704, + -1, 706, -1, 708, -1, 710, -1, 712, -1, -1, + 715, -1, -1, 718, -1, -1, -1, -1, 723, 724, + -1, 726, -1, -1, -1, 730, -1, -1, -1, -1, + 735, 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, 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, 833, -1, + 835, -1, -1, -1, -1, -1, -1, -1, 843, -1, + -1, 846, -1, -1, -1, 850, -1, 852, -1, 854, + 855, -1, -1, -1, -1, -1, 861, -1, -1, 864, + -1, -1, 867, 868, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 884, + -1, 886, -1, 888, -1, -1, -1, 892, 893, 894, + -1, -1, 897, 898, -1, 900, 901, -1, 903, -1, + -1, 906, -1, -1, -1, -1, 911, 912, 913, -1, + 915, -1, 917, 918, -1, -1, -1, -1, -1, -1, + -1, -1, 927, 928, 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, -1, 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, 954, -1, -1, - 957, 958, 959, -1, -1, -1, -1, 964, 965, -1, - -1, -1, -1, 970, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 981, -1, -1, -1, -1, 986, - 987, 988, -1, 990, 991, 992, 993, -1, 995, -1, - 997, -1, -1, -1, 1001, -1, 1003, -1, 1005, -1, - -1, -1, 1009, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 989, -1, -1, -1, -1, 994, + 995, 996, -1, -1, -1, -1, 1001, 1002, -1, -1, + -1, -1, 1007, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 1018, -1, -1, -1, -1, -1, -1, + 1025, 1026, 1027, -1, 1029, 1030, 1031, 1032, -1, 1034, + -1, 1036, -1, -1, -1, 1040, -1, 1042, -1, 1044, + -1, -1, -1, 1048, -1, 196, -1, 198, -1, 200, + -1, -1, 203, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 196, -1, 198, -1, 200, -1, -1, 203, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1047, -1, 1049, -1, 1051, -1, -1, -1, 1055, 1056, - -1, -1, -1, 1060, 1061, -1, 1063, -1, -1, 1066, - -1, 1068, -1, -1, -1, -1, -1, -1, -1, -1, - 1077, -1, -1, -1, -1, 1082, -1, 1084, 1085, -1, - -1, -1, -1, -1, -1, -1, 817, 818, 819, 820, + -1, -1, 1087, -1, 1089, -1, 1091, -1, -1, -1, + 1095, 1096, -1, -1, -1, 1100, 1101, -1, 1103, -1, + -1, 1106, -1, 1108, -1, -1, -1, -1, -1, -1, + -1, -1, 1117, -1, -1, -1, -1, 1122, -1, 1124, + 1125, -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, 844, -1, -1, -1, -1, 1125, 1126, - -1, 1128, 1129, -1, 1131, 1132, -1, -1, -1, -1, - 1137, 1138, -1, 1140, -1, -1, -1, -1, -1, -1, - 1147, 1148, -1, -1, -1, -1, -1, -1, -1, 324, - -1, -1, -1, -1, -1, -1, 331, -1, 333, 334, - -1, -1, -1, 1170, 1171, 1172, -1, -1, -1, -1, - -1, -1, -1, 1180, 349, -1, -1, -1, -1, 354, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 1205, 1206, - -1, -1, -1, -1, -1, -1, -1, 1214, 1215, 1216, - 1217, 1218, 1219, -1, -1, 1222, -1, 1224, -1, 1226, - -1, -1, -1, -1, 1231, -1, -1, -1, -1, 960, - -1, -1, 963, -1, -1, -1, -1, 968, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 979, -1, - -1, -1, 427, -1, -1, -1, 1263, -1, 1265, -1, - -1, -1, -1, 438, -1, 1272, -1, 1274, -1, -1, - -1, -1, 1279, -1, -1, -1, 1283, -1, -1, -1, - 1287, -1, 457, -1, -1, 1292, -1, -1, 463, 464, - -1, -1, 467, -1, -1, 470, -1, -1, -1, -1, - -1, -1, 477, -1, -1, 480, -1, -1, -1, -1, - 485, -1, -1, -1, -1, -1, -1, -1, -1, 494, - -1, -1, -1, 1054, -1, -1, -1, 1334, -1, -1, - 1337, 1338, 507, -1, -1, 1342, 511, -1, -1, -1, + 1165, 1166, -1, 1168, 1169, -1, 1171, 1172, -1, -1, + -1, -1, 1177, 1178, -1, 1180, -1, -1, -1, -1, + -1, -1, 1187, 1188, 335, -1, -1, -1, -1, -1, + -1, 342, -1, 344, 345, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1210, 1211, 1212, -1, 360, + -1, -1, -1, -1, 365, 1220, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 527, -1, -1, -1, -1, -1, -1, 534, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1245, 1246, -1, -1, -1, -1, -1, -1, -1, 1254, + 1255, 1256, 1257, 1258, 1259, -1, -1, 1262, -1, 1264, + -1, 1266, -1, -1, -1, -1, 1271, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 565, -1, -1, -1, -1, 570, -1, -1, -1, 574, - -1, -1, -1, 1134, -1, 580, -1, 582, -1, -1, - -1, 586, -1, -1, -1, -1, -1, 592, 1149, -1, - -1, -1, -1, -1, 599, -1, -1, -1, -1, -1, + 308, 309, -1, 311, 445, -1, -1, -1, 1303, -1, + 1305, -1, -1, -1, -1, 456, -1, 1312, -1, 1314, + -1, -1, -1, -1, 1319, -1, -1, -1, 1323, -1, + -1, -1, 1327, -1, 475, -1, -1, 1332, -1, -1, + 481, 482, -1, -1, 485, -1, -1, 488, -1, -1, + -1, -1, -1, -1, 495, -1, -1, 498, -1, -1, + -1, -1, 503, -1, 505, -1, -1, -1, -1, -1, + -1, -1, -1, 514, -1, -1, -1, -1, -1, 1374, + -1, -1, 1377, 1378, -1, -1, 527, 1382, -1, -1, + 531, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 547, -1, -1, -1, + -1, -1, -1, 554, -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, 624, - -1, -1, 627, 628, 629, 630, -1, -1, -1, -1, - -1, -1, 637, -1, -1, -1, -1, -1, -1, -1, - -1, 646, -1, 648, -1, 650, 651, 652, 653, 654, - 655, 656, -1, -1, -1, -1, 661, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1228, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 585, -1, -1, -1, -1, -1, + 591, -1, -1, -1, 595, -1, -1, -1, 466, -1, + 601, -1, 603, 471, -1, -1, 607, -1, -1, -1, + 478, 479, 613, -1, -1, -1, -1, -1, -1, 620, + -1, -1, -1, -1, -1, -1, -1, -1, 496, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 1256, -1, -1, -1, 1260, - 1261, -1, 1263, -1, 1265, -1, -1, -1, 1269, 1270, - -1, 1272, -1, 1274, -1, 1276, 1277, -1, 1279, 1280, - 1281, -1, 1283, -1, 1285, -1, 1287, 1288, 733, 1290, - 735, 1292, 1293, -1, 1295, -1, 1297, -1, -1, -1, - -1, -1, -1, 748, -1, 750, -1, -1, -1, -1, + -1, -1, -1, -1, 645, -1, -1, 648, 649, 650, + 651, -1, -1, -1, -1, -1, -1, 658, -1, -1, + -1, -1, -1, -1, -1, -1, 667, -1, 669, -1, + -1, 672, -1, 674, -1, 676, -1, -1, -1, -1, + -1, 682, -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, 1336, 1337, -1, 1339, -1, - 1341, 1342, -1, 1344, 1345, 1346, 1347, 1348, -1, -1, - -1, -1, -1, 798, -1, -1, -1, -1, -1, -1, - -1, 806, -1, -1, 1365, -1, 1367, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 822, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 845, -1, -1, -1, -1, -1, -1, -1, 853, -1, - -1, -1, -1, -1, -1, -1, -1, 862, -1, -1, - -1, -1, 867, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 879, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 890, -1, -1, -1, -1, - -1, -1, 897, -1, 899, 900, 901, 902, -1, -1, - -1, -1, 907, 908, -1, 910, -1, 912, -1, -1, - 915, -1, 917, 918, -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, 754, -1, 756, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 769, -1, + 771, -1, -1, -1, -1, -1, -1, 778, -1, 780, + -1, 782, -1, 784, -1, -1, 654, 655, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 671, -1, 673, -1, 675, -1, 677, + -1, -1, -1, -1, -1, -1, -1, -1, 819, -1, + -1, -1, -1, -1, -1, -1, 827, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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, -1, -1, -1, -1, -1, - 985, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 1000, -1, 1002, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 1018, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 1036, -1, -1, -1, -1, 1041, -1, -1, -1, - 1045, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 891, -1, -1, -1, -1, 896, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 908, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 919, -1, + -1, -1, -1, -1, -1, 926, -1, -1, 929, 930, + 931, 932, -1, -1, -1, -1, 937, -1, -1, 940, + -1, 942, -1, 944, -1, -1, -1, -1, -1, 950, + -1, 952, 953, 954, -1, -1, -1, -1, -1, -1, + 961, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 840, 841, 842, 843, -1, -1, -1, 847, + 848, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 858, -1, -1, 861, 862, -1, -1, -1, -1, -1, + -1, 869, 870, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 882, -1, -1, -1, -1, -1, + -1, -1, -1, 1024, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 1039, -1, + 1041, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1057, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1076, -1, -1, -1, -1, + 1081, -1, -1, -1, 1085, -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, - 1095, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1105, -1, 1107, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 997, + -1, -1, 1000, -1, 1135, -1, -1, 1005, -1, -1, + 1008, -1, -1, -1, 1145, -1, 1147, -1, 1016, -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, - 1145, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 1158, -1, -1, -1, -1, -1, -1, - -1, 1166, -1, 1168, 1169, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 1185, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1198, -1, -1, + -1, -1, -1, -1, -1, 1206, -1, 1208, 1209, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1094, -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, 1212, -1, -1, - -1, -1, -1, -1, -1, 1220, -1, -1, -1, -1, + -1, 1252, -1, -1, -1, -1, -1, -1, -1, 1260, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 1236, -1, -1, -1, -1, -1, -1, -1, 1244, - -1, -1, -1, -1, -1, -1, -1, 1252, -1, -1, + -1, -1, -1, -1, -1, 1276, -1, -1, -1, -1, + -1, -1, -1, 1284, -1, -1, -1, -1, -1, -1, + -1, 1292, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1174, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1189, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 1339, 1340, -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, 1299, 1300, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 1380, + -1, -1, 1383, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1268, -1, -1, -1, -1, 1406, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 1296, -1, + -1, -1, 1300, 1301, -1, 1303, -1, 1305, -1, -1, + -1, 1309, 1310, -1, 1312, -1, 1314, -1, 1316, 1317, + -1, 1319, 1320, 1321, -1, 1323, -1, 1325, -1, 1327, + 1328, -1, 1330, -1, 1332, 1333, -1, 1335, -1, 1337, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 1340, -1, -1, 1343, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 1366 + -1, -1, -1, -1, -1, -1, -1, -1, 1376, 1377, + -1, 1379, -1, 1381, 1382, -1, 1384, 1385, 1386, 1387, + 1388, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1405, -1, 1407 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -1956,215 +1990,220 @@ static const yytype_uint16 yystos[] = { 0, 4, 5, 10, 15, 17, 18, 24, 27, 34, 35, 37, 39, 44, 46, 49, 52, 60, 63, 65, - 66, 67, 68, 76, 77, 78, 79, 80, 82, 83, - 84, 85, 86, 87, 89, 90, 91, 164, 165, 166, - 237, 239, 303, 304, 307, 309, 330, 331, 332, 333, - 334, 335, 338, 339, 341, 343, 351, 352, 358, 359, - 370, 372, 383, 384, 385, 392, 393, 394, 395, 396, - 397, 398, 399, 400, 401, 402, 403, 404, 405, 407, - 428, 429, 430, 432, 434, 435, 441, 442, 447, 452, - 455, 458, 461, 462, 465, 470, 472, 475, 477, 487, - 489, 490, 493, 495, 496, 0, 158, 159, 201, 201, - 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, - 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, - 201, 146, 204, 240, 204, 310, 204, 337, 337, 204, - 344, 204, 353, 337, 204, 373, 337, 353, 337, 353, - 337, 353, 337, 353, 204, 443, 204, 466, 332, 333, - 334, 335, 358, 384, 385, 395, 399, 403, 428, 441, - 447, 452, 455, 458, 461, 471, 473, 474, 204, 478, - 478, 478, 40, 479, 480, 162, 203, 203, 203, 203, - 203, 203, 203, 203, 203, 203, 354, 203, 354, 203, - 354, 203, 203, 406, 203, 203, 160, 161, 202, 203, - 203, 203, 203, 203, 201, 147, 148, 150, 151, 152, - 153, 154, 167, 168, 169, 171, 173, 174, 177, 179, - 180, 204, 241, 61, 311, 313, 19, 28, 56, 304, - 309, 320, 321, 340, 351, 366, 367, 431, 433, 436, - 438, 439, 440, 320, 340, 431, 433, 171, 345, 341, - 360, 361, 363, 364, 365, 366, 367, 3, 25, 374, - 375, 70, 307, 309, 320, 386, 393, 448, 449, 450, - 451, 23, 237, 355, 356, 202, 71, 397, 453, 454, - 202, 72, 401, 456, 457, 202, 73, 405, 459, 460, - 50, 51, 237, 408, 409, 411, 412, 202, 64, 444, - 445, 462, 463, 495, 74, 75, 467, 468, 479, 479, - 479, 41, 481, 482, 166, 179, 149, 167, 178, 171, - 203, 238, 203, 305, 308, 201, 201, 203, 201, 203, - 201, 201, 203, 203, 203, 203, 203, 203, 203, 354, - 203, 201, 201, 203, 371, 201, 201, 203, 203, 203, - 201, 203, 258, 203, 201, 203, 203, 201, 203, 203, - 201, 203, 203, 201, 258, 258, 201, 203, 258, 201, - 203, 201, 203, 201, 203, 203, 203, 203, 201, 202, - 172, 175, 176, 180, 179, 32, 33, 168, 204, 242, - 243, 244, 246, 247, 202, 62, 311, 316, 317, 341, - 202, 202, 204, 314, 310, 351, 57, 322, 323, 6, - 16, 81, 267, 268, 270, 271, 273, 336, 347, 348, - 204, 368, 368, 48, 414, 416, 414, 351, 336, 414, - 414, 171, 346, 202, 370, 368, 368, 9, 237, 377, - 379, 202, 204, 376, 310, 393, 273, 387, 414, 368, - 237, 237, 204, 357, 267, 414, 368, 267, 414, 368, - 267, 414, 368, 179, 183, 185, 204, 410, 408, 204, - 413, 414, 368, 463, 179, 469, 481, 25, 418, 419, - 481, 47, 497, 500, 166, 179, 203, 203, 201, 201, - 305, 308, 203, 306, 201, 203, 203, 312, 203, 203, - 203, 325, 201, 201, 202, 203, 201, 203, 203, 203, - 201, 203, 203, 202, 203, 203, 203, 342, 203, 203, - 203, 258, 371, 201, 258, 203, 203, 201, 202, 203, - 203, 258, 258, 202, 202, 203, 203, 202, 203, 203, - 202, 203, 203, 154, 156, 182, 184, 188, 191, 202, - 258, 202, 203, 203, 203, 464, 167, 202, 203, 203, - 488, 201, 203, 203, 206, 201, 202, 243, 246, 204, - 245, 204, 248, 237, 319, 168, 318, 316, 237, 315, - 202, 311, 336, 58, 59, 326, 328, 202, 179, 324, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 274, 275, 276, 267, 204, 349, - 320, 340, 320, 340, 267, 204, 417, 267, 336, 267, - 267, 7, 11, 237, 259, 263, 202, 267, 320, 340, - 320, 340, 204, 380, 202, 311, 387, 274, 267, 320, - 393, 267, 397, 267, 401, 267, 405, 179, 186, 179, - 192, 267, 436, 438, 439, 440, 446, 26, 29, 30, - 31, 53, 54, 55, 207, 209, 210, 211, 212, 213, - 214, 215, 218, 219, 220, 222, 223, 228, 230, 233, - 234, 237, 249, 250, 463, 202, 179, 418, 38, 43, - 207, 379, 421, 425, 426, 485, 486, 202, 204, 420, - 45, 494, 207, 202, 478, 203, 202, 202, 306, 202, - 306, 312, 203, 202, 201, 167, 202, 203, 203, 203, - 203, 203, 203, 437, 203, 437, 202, 203, 202, 202, - 202, 202, 258, 258, 201, 202, 203, 203, 362, 203, - 362, 203, 203, 202, 203, 202, 203, 202, 202, 202, - 202, 202, 202, 202, 184, 182, 155, 157, 180, 181, - 189, 192, 197, 198, 199, 202, 203, 203, 201, 203, - 208, 201, 203, 208, 201, 203, 208, 201, 203, 208, - 201, 203, 208, 201, 208, 201, 464, 203, 476, 201, - 488, 488, 201, 206, 201, 203, 327, 201, 203, 246, - 311, 204, 329, 179, 150, 151, 152, 277, 277, 277, - 170, 172, 350, 351, 347, 202, 351, 202, 418, 204, - 265, 351, 7, 12, 257, 262, 347, 369, 202, 351, - 202, 170, 381, 311, 277, 393, 179, 187, 192, 179, - 193, 181, 200, 370, 211, 237, 249, 214, 218, 237, - 249, 204, 216, 222, 228, 233, 204, 221, 228, 233, - 168, 224, 233, 168, 231, 183, 204, 235, 146, 205, - 42, 207, 421, 425, 483, 484, 485, 202, 380, 380, - 318, 237, 202, 370, 414, 475, 489, 491, 418, 327, - 258, 258, 258, 203, 258, 171, 202, 437, 437, 203, - 415, 203, 362, 201, 203, 362, 203, 378, 258, 202, - 184, 200, 181, 190, 197, 193, 202, 208, 203, 208, - 202, 203, 208, 203, 208, 208, 202, 203, 208, 208, - 203, 208, 203, 203, 202, 476, 476, 203, 206, 201, - 206, 203, 203, 202, 202, 203, 202, 202, 202, 202, - 257, 202, 202, 237, 421, 425, 202, 171, 266, 202, - 265, 369, 202, 7, 11, 12, 13, 255, 256, 382, - 202, 202, 179, 194, 195, 217, 219, 222, 228, 233, - 228, 233, 233, 233, 168, 225, 168, 232, 183, 204, - 236, 485, 166, 381, 204, 427, 203, 379, 425, 498, - 501, 203, 203, 203, 258, 258, 415, 415, 258, 203, - 201, 258, 203, 167, 197, 202, 203, 203, 203, 203, - 208, 208, 208, 208, 203, 203, 229, 202, 206, 202, - 203, 327, 494, 201, 203, 499, 8, 278, 281, 279, - 281, 280, 281, 202, 266, 265, 278, 179, 196, 197, - 222, 228, 233, 228, 233, 233, 233, 168, 226, 259, - 202, 7, 11, 12, 13, 14, 69, 422, 423, 424, - 202, 201, 380, 207, 425, 501, 202, 203, 269, 201, - 206, 201, 203, 272, 201, 258, 203, 203, 388, 197, - 203, 203, 203, 208, 203, 327, 201, 491, 203, 499, - 499, 7, 11, 12, 13, 14, 69, 88, 207, 251, - 252, 253, 254, 260, 264, 278, 302, 204, 282, 282, - 207, 280, 282, 202, 266, 36, 207, 302, 389, 390, - 228, 233, 233, 233, 168, 227, 202, 265, 202, 381, - 201, 201, 269, 206, 203, 203, 272, 203, 258, 203, - 206, 206, 201, 203, 202, 203, 261, 203, 492, 258, - 265, 265, 106, 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, 283, 286, 295, 295, 106, 114, 139, 140, - 288, 291, 295, 202, 389, 204, 391, 233, 266, 202, - 207, 485, 494, 202, 202, 203, 261, 203, 203, 203, - 203, 202, 203, 203, 293, 203, 203, 203, 203, 202, - 203, 206, 327, 258, 206, 201, 266, 202, 20, 22, - 237, 252, 284, 296, 297, 300, 301, 284, 21, 237, - 252, 285, 298, 299, 300, 285, 237, 252, 287, 300, - 237, 260, 294, 300, 202, 237, 289, 296, 300, 284, - 237, 290, 298, 300, 290, 237, 292, 300, 202, 491, - 258, 258, 258, 203, 258, 201, 203, 258, 201, 258, - 258, 203, 258, 201, 203, 258, 258, 258, 203, 258, - 258, 258, 203, 258, 258, 203, 258, 258, 258, 203, - 258, 258, 258, 258, 202, 202, 252, 300, 168, 252, - 179, 252, 300, 168, 252, 252, 260, 300, 300, 492, - 258, 203, 258, 203, 258, 202, 258, 203, 258, 202, - 258, 258, 258, 258, 258, 252, 257, 252, 258, 202, - 258 + 66, 67, 68, 76, 77, 79, 80, 81, 83, 84, + 85, 86, 87, 88, 90, 91, 92, 165, 166, 167, + 238, 240, 304, 305, 308, 310, 331, 332, 333, 334, + 335, 336, 339, 340, 342, 344, 352, 353, 359, 360, + 371, 373, 384, 385, 386, 393, 394, 395, 396, 397, + 398, 399, 400, 401, 402, 403, 404, 405, 406, 408, + 429, 430, 431, 433, 435, 436, 442, 443, 448, 453, + 456, 459, 462, 463, 466, 471, 473, 476, 480, 493, + 497, 498, 503, 505, 506, 0, 159, 160, 202, 202, + 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, + 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, + 202, 147, 205, 241, 205, 311, 205, 338, 338, 205, + 345, 205, 354, 338, 205, 374, 338, 354, 338, 354, + 338, 354, 338, 354, 205, 444, 205, 467, 333, 334, + 335, 336, 359, 385, 386, 396, 400, 404, 429, 442, + 448, 453, 456, 459, 462, 472, 474, 475, 205, 481, + 481, 481, 40, 485, 486, 163, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 355, 204, 355, 204, + 355, 204, 204, 407, 204, 204, 161, 162, 203, 204, + 204, 477, 478, 204, 494, 495, 204, 499, 500, 204, + 202, 148, 149, 151, 152, 153, 154, 155, 168, 169, + 170, 172, 174, 175, 178, 180, 181, 205, 242, 61, + 312, 314, 19, 28, 56, 305, 310, 321, 322, 341, + 352, 367, 368, 432, 434, 437, 439, 440, 441, 321, + 341, 432, 434, 172, 346, 342, 361, 362, 364, 365, + 366, 367, 368, 3, 25, 375, 376, 70, 308, 310, + 321, 387, 394, 449, 450, 451, 452, 23, 238, 356, + 357, 203, 71, 398, 454, 455, 203, 72, 402, 457, + 458, 203, 73, 406, 460, 461, 50, 51, 238, 409, + 410, 412, 413, 203, 64, 445, 446, 463, 464, 505, + 74, 75, 468, 469, 78, 482, 483, 485, 482, 485, + 482, 485, 41, 487, 488, 167, 180, 150, 168, 179, + 172, 204, 239, 204, 306, 309, 202, 202, 204, 202, + 204, 202, 202, 204, 204, 204, 204, 204, 204, 204, + 355, 204, 202, 202, 204, 372, 202, 202, 204, 204, + 204, 202, 204, 259, 204, 202, 204, 204, 202, 204, + 204, 202, 204, 204, 202, 259, 259, 202, 204, 259, + 202, 204, 202, 204, 202, 204, 478, 202, 204, 204, + 495, 204, 204, 500, 204, 204, 202, 203, 173, 176, + 177, 181, 180, 32, 33, 169, 205, 243, 244, 245, + 247, 248, 203, 62, 312, 317, 318, 342, 203, 203, + 205, 315, 311, 352, 57, 323, 324, 6, 16, 82, + 268, 269, 271, 272, 274, 337, 348, 349, 205, 369, + 369, 48, 415, 417, 415, 352, 337, 415, 415, 172, + 347, 203, 371, 369, 369, 9, 238, 378, 380, 203, + 205, 377, 311, 394, 274, 388, 415, 369, 238, 238, + 205, 358, 268, 415, 369, 268, 415, 369, 268, 415, + 369, 180, 184, 186, 205, 411, 409, 205, 414, 415, + 369, 464, 180, 470, 205, 484, 487, 25, 419, 420, + 487, 47, 507, 512, 167, 180, 204, 204, 202, 202, + 306, 309, 204, 307, 202, 204, 204, 313, 204, 204, + 204, 326, 202, 202, 203, 204, 202, 204, 204, 204, + 202, 204, 204, 203, 204, 204, 204, 343, 204, 204, + 204, 259, 372, 202, 259, 204, 204, 202, 203, 204, + 204, 259, 259, 203, 203, 204, 204, 203, 204, 204, + 203, 204, 204, 155, 157, 183, 185, 189, 192, 203, + 259, 203, 204, 204, 204, 465, 168, 203, 203, 204, + 204, 496, 202, 204, 204, 207, 202, 203, 244, 247, + 205, 246, 205, 249, 238, 320, 169, 319, 317, 238, + 316, 203, 312, 337, 58, 59, 327, 329, 203, 180, + 325, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 275, 276, 277, 268, 205, + 350, 321, 341, 321, 341, 268, 205, 418, 268, 337, + 268, 268, 7, 11, 238, 260, 264, 203, 268, 321, + 341, 321, 341, 205, 381, 203, 312, 388, 275, 268, + 321, 394, 268, 398, 268, 402, 268, 406, 180, 187, + 180, 193, 268, 437, 439, 440, 441, 447, 26, 29, + 30, 31, 53, 54, 55, 208, 210, 211, 212, 213, + 214, 215, 216, 219, 220, 221, 223, 224, 229, 231, + 234, 235, 238, 250, 251, 464, 203, 180, 419, 38, + 43, 208, 380, 422, 426, 427, 491, 492, 203, 205, + 421, 45, 504, 208, 203, 481, 204, 203, 203, 307, + 203, 307, 313, 204, 203, 202, 168, 203, 204, 204, + 204, 204, 204, 204, 438, 204, 438, 203, 204, 203, + 203, 203, 203, 259, 259, 202, 203, 204, 204, 363, + 204, 363, 204, 204, 203, 204, 203, 204, 259, 203, + 259, 203, 259, 203, 259, 185, 183, 156, 158, 181, + 182, 190, 193, 198, 199, 200, 203, 204, 204, 202, + 204, 209, 202, 204, 209, 202, 204, 209, 202, 204, + 209, 202, 204, 209, 202, 209, 202, 465, 204, 479, + 202, 496, 496, 202, 207, 202, 204, 328, 202, 204, + 508, 509, 247, 312, 205, 330, 180, 151, 152, 153, + 278, 278, 278, 171, 173, 351, 352, 238, 348, 203, + 352, 203, 419, 205, 266, 352, 7, 12, 238, 258, + 263, 348, 370, 203, 352, 203, 171, 382, 312, 278, + 394, 203, 203, 203, 203, 180, 188, 193, 180, 194, + 182, 201, 371, 212, 238, 250, 215, 219, 238, 250, + 205, 217, 223, 229, 234, 205, 222, 229, 234, 169, + 225, 234, 169, 232, 184, 205, 236, 147, 206, 42, + 208, 422, 426, 489, 490, 491, 203, 381, 381, 319, + 238, 203, 371, 415, 476, 497, 501, 419, 482, 328, + 259, 259, 259, 204, 259, 172, 203, 438, 259, 259, + 438, 204, 416, 204, 363, 259, 202, 204, 259, 259, + 363, 204, 379, 259, 259, 185, 201, 182, 191, 198, + 194, 259, 209, 204, 209, 203, 204, 209, 204, 209, + 209, 203, 204, 209, 209, 204, 209, 204, 204, 203, + 479, 479, 204, 207, 202, 207, 204, 204, 203, 203, + 204, 204, 509, 203, 203, 203, 203, 258, 203, 203, + 238, 422, 426, 203, 172, 267, 203, 266, 370, 203, + 7, 11, 12, 13, 256, 257, 383, 203, 203, 203, + 180, 195, 196, 203, 218, 220, 223, 229, 234, 229, + 234, 234, 234, 169, 226, 169, 233, 184, 205, 237, + 491, 167, 382, 205, 428, 204, 380, 426, 510, 513, + 204, 204, 204, 259, 259, 416, 416, 259, 204, 259, + 202, 259, 204, 168, 198, 203, 204, 204, 204, 204, + 209, 209, 209, 209, 204, 204, 230, 203, 207, 203, + 204, 328, 504, 202, 204, 511, 8, 279, 282, 280, + 282, 281, 282, 203, 267, 266, 279, 180, 197, 198, + 223, 229, 234, 229, 234, 234, 234, 169, 227, 260, + 203, 7, 11, 12, 13, 14, 69, 423, 424, 425, + 203, 202, 381, 208, 426, 513, 203, 204, 270, 202, + 207, 202, 204, 273, 202, 259, 204, 204, 389, 198, + 204, 204, 204, 209, 204, 328, 202, 501, 204, 511, + 511, 7, 11, 12, 13, 14, 69, 89, 208, 252, + 253, 254, 255, 261, 265, 279, 303, 205, 283, 283, + 208, 281, 283, 203, 267, 36, 208, 303, 390, 391, + 229, 234, 234, 234, 169, 228, 203, 266, 203, 382, + 202, 202, 270, 207, 204, 204, 273, 204, 259, 204, + 207, 207, 202, 204, 203, 204, 262, 204, 502, 259, + 266, 266, 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, 284, 287, 296, 296, 107, 115, 140, 141, + 289, 292, 296, 203, 390, 205, 392, 234, 267, 203, + 208, 491, 504, 203, 203, 204, 262, 204, 204, 204, + 204, 203, 204, 204, 294, 204, 204, 204, 204, 203, + 204, 207, 328, 259, 207, 202, 267, 203, 20, 22, + 238, 253, 285, 297, 298, 301, 302, 285, 21, 238, + 253, 286, 299, 300, 301, 286, 238, 253, 288, 301, + 238, 261, 295, 301, 203, 238, 290, 297, 301, 285, + 238, 291, 299, 301, 291, 238, 293, 301, 203, 501, + 259, 259, 259, 204, 259, 202, 204, 259, 202, 259, + 259, 204, 259, 202, 204, 259, 259, 259, 204, 259, + 259, 259, 204, 259, 259, 204, 259, 259, 259, 204, + 259, 259, 259, 259, 203, 203, 253, 301, 169, 253, + 180, 253, 301, 169, 253, 253, 261, 301, 301, 502, + 259, 204, 259, 204, 259, 203, 259, 204, 259, 203, + 259, 259, 259, 259, 259, 253, 258, 253, 259, 203, + 259 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint16 yyr1[] = { - 0, 163, 164, 164, 164, 164, 164, 164, 164, 164, - 164, 164, 165, 165, 165, 165, 165, 165, 166, 166, - 167, 168, 168, 169, 170, 171, 171, 172, 172, 173, - 174, 175, 176, 177, 177, 178, 178, 179, 179, 179, - 179, 180, 180, 181, 182, 183, 183, 183, 184, 184, - 185, 186, 187, 188, 189, 189, 190, 190, 191, 192, - 193, 194, 194, 194, 195, 196, 197, 197, 198, 199, - 199, 200, 200, 201, 201, 202, 202, 203, 204, 205, - 206, 206, 207, 207, 207, 208, 208, 208, 209, 209, - 210, 210, 210, 211, 211, 211, 211, 212, 213, 214, - 215, 216, 217, 217, 217, 217, 217, 217, 217, 217, - 217, 217, 217, 217, 217, 217, 217, 218, 218, 218, - 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, - 218, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 229, 230, 231, 232, 233, 234, 235, - 235, 236, 236, 237, 238, 238, 238, 238, 238, 238, - 238, 239, 240, 241, 241, 242, 242, 243, 244, 245, - 246, 247, 248, 249, 250, 251, 251, 252, 253, 254, - 254, 254, 254, 254, 255, 256, 256, 256, 256, 257, - 258, 258, 259, 260, 261, 261, 262, 262, 263, 263, - 264, 264, 265, 266, 267, 267, 267, 268, 269, 269, - 269, 269, 270, 271, 272, 272, 272, 273, 274, 274, - 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, - 276, 276, 277, 277, 277, 278, 279, 280, 281, 282, - 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, - 284, 284, 284, 284, 284, 284, 284, 285, 285, 285, - 285, 285, 285, 285, 285, 286, 286, 287, 287, 287, - 287, 288, 288, 288, 288, 288, 288, 288, 288, 288, - 289, 289, 289, 289, 290, 290, 290, 290, 291, 291, - 292, 292, 293, 293, 294, 294, 294, 294, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 296, 297, 298, 299, 300, 301, - 302, 303, 303, 304, 305, 305, 306, 306, 307, 308, - 308, 309, 310, 311, 312, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 323, 324, 324, 324, - 325, 325, 326, 327, 327, 328, 328, 329, 330, 330, - 330, 331, 331, 332, 333, 334, 335, 336, 336, 337, - 338, 338, 339, 339, 340, 340, 341, 342, 342, 342, - 343, 343, 344, 345, 346, 347, 348, 348, 349, 350, - 350, 351, 352, 352, 352, 353, 354, 354, 354, 354, - 355, 356, 357, 358, 359, 359, 360, 360, 360, 360, - 361, 362, 362, 362, 362, 363, 364, 365, 366, 367, - 368, 369, 370, 371, 371, 371, 372, 373, 374, 375, - 375, 376, 377, 378, 378, 379, 380, 381, 382, 383, - 383, 384, 385, 386, 386, 387, 388, 388, 388, 388, - 388, 389, 390, 391, 392, 392, 393, 394, 394, 394, - 395, 396, 396, 397, 398, 398, 399, 400, 401, 402, - 402, 403, 404, 405, 406, 406, 406, 406, 406, 407, - 407, 408, 409, 410, 410, 411, 412, 413, 414, 415, - 415, 415, 415, 416, 417, 418, 419, 420, 421, 422, - 423, 424, 424, 424, 424, 424, 424, 425, 426, 427, - 428, 428, 428, 429, 429, 430, 431, 431, 432, 433, - 433, 434, 435, 436, 437, 437, 438, 439, 440, 441, - 442, 443, 444, 445, 446, 446, 446, 446, 447, 448, - 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, - 458, 459, 460, 461, 462, 462, 462, 462, 462, 462, - 462, 462, 462, 462, 462, 462, 463, 463, 464, 464, - 464, 465, 466, 467, 468, 468, 469, 469, 469, 470, - 471, 471, 472, 473, 473, 473, 473, 473, 473, 473, - 473, 473, 473, 473, 473, 473, 473, 474, 474, 474, - 474, 474, 474, 474, 475, 476, 476, 476, 476, 476, - 476, 476, 477, 478, 479, 480, 481, 482, 483, 484, - 485, 486, 487, 488, 488, 488, 488, 488, 489, 490, - 491, 491, 491, 491, 492, 492, 492, 492, 493, 494, - 495, 496, 497, 498, 498, 499, 499, 499, 499, 500, - 501 + 0, 164, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 166, 166, 166, 166, 166, 166, 167, 167, + 168, 169, 169, 170, 171, 172, 172, 173, 173, 174, + 175, 176, 177, 178, 178, 179, 179, 180, 180, 180, + 180, 181, 181, 182, 183, 184, 184, 184, 185, 185, + 186, 187, 188, 189, 190, 190, 191, 191, 192, 193, + 194, 195, 195, 195, 196, 197, 198, 198, 199, 200, + 200, 201, 201, 202, 202, 203, 203, 204, 205, 206, + 207, 207, 208, 208, 208, 209, 209, 209, 210, 210, + 211, 211, 211, 212, 212, 212, 212, 213, 214, 215, + 216, 217, 218, 218, 218, 218, 218, 218, 218, 218, + 218, 218, 218, 218, 218, 218, 218, 219, 219, 219, + 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, + 219, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 230, 231, 232, 233, 234, 235, 236, + 236, 237, 237, 238, 239, 239, 239, 239, 239, 239, + 239, 240, 241, 242, 242, 243, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 252, 253, 254, 255, + 255, 255, 255, 255, 256, 257, 257, 257, 257, 258, + 259, 259, 260, 261, 262, 262, 263, 263, 264, 264, + 265, 265, 266, 267, 268, 268, 268, 269, 270, 270, + 270, 270, 271, 272, 273, 273, 273, 274, 275, 275, + 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, + 277, 277, 278, 278, 278, 279, 280, 281, 282, 283, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 285, + 285, 285, 285, 285, 285, 285, 285, 286, 286, 286, + 286, 286, 286, 286, 286, 287, 287, 288, 288, 288, + 288, 289, 289, 289, 289, 289, 289, 289, 289, 289, + 290, 290, 290, 290, 291, 291, 291, 291, 292, 292, + 293, 293, 294, 294, 295, 295, 295, 295, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, + 296, 296, 296, 296, 297, 298, 299, 300, 301, 302, + 303, 304, 304, 305, 306, 306, 307, 307, 308, 309, + 309, 310, 311, 312, 313, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 325, 325, + 326, 326, 327, 328, 328, 329, 329, 330, 331, 331, + 331, 332, 332, 333, 334, 335, 336, 337, 337, 338, + 339, 339, 340, 340, 341, 341, 342, 343, 343, 343, + 344, 344, 345, 346, 347, 348, 349, 349, 350, 351, + 351, 352, 353, 353, 353, 354, 355, 355, 355, 355, + 356, 357, 358, 359, 360, 360, 361, 361, 361, 361, + 362, 363, 363, 363, 363, 363, 364, 365, 366, 367, + 368, 369, 370, 371, 372, 372, 372, 373, 374, 375, + 376, 376, 377, 378, 379, 379, 380, 381, 382, 383, + 384, 384, 385, 386, 387, 387, 388, 389, 389, 389, + 389, 389, 390, 391, 392, 393, 393, 394, 395, 395, + 395, 396, 397, 397, 398, 399, 399, 400, 401, 402, + 403, 403, 404, 405, 406, 407, 407, 407, 407, 407, + 408, 408, 409, 410, 411, 411, 412, 413, 414, 415, + 416, 416, 416, 416, 417, 418, 419, 420, 421, 422, + 423, 424, 425, 425, 425, 425, 425, 425, 426, 427, + 428, 429, 429, 429, 430, 430, 431, 432, 432, 433, + 434, 434, 435, 436, 437, 438, 438, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 447, 447, 447, 447, + 448, 449, 449, 450, 451, 452, 453, 454, 455, 456, + 457, 458, 459, 460, 461, 462, 463, 463, 463, 463, + 463, 463, 463, 463, 463, 463, 463, 463, 464, 464, + 465, 465, 465, 466, 467, 468, 469, 469, 470, 470, + 470, 471, 472, 472, 473, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 475, + 475, 475, 475, 475, 475, 475, 476, 477, 477, 478, + 479, 479, 479, 479, 479, 479, 479, 480, 481, 482, + 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, + 493, 494, 494, 495, 496, 496, 496, 496, 496, 497, + 498, 499, 499, 500, 501, 501, 501, 501, 502, 502, + 502, 502, 503, 504, 505, 506, 507, 508, 508, 509, + 510, 510, 511, 511, 511, 511, 512, 513 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ @@ -2213,31 +2252,32 @@ static const yytype_uint8 yyr2[] = 1, 1, 1, 1, 1, 6, 1, 1, 1, 4, 2, 7, 1, 1, 1, 1, 0, 2, 3, 5, 4, 1, 1, 10, 1, 1, 1, 1, 1, 1, - 7, 0, 2, 4, 2, 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, 2, 9, 7, 9, 10, - 1, 1, 8, 1, 1, 1, 1, 1, 10, 1, - 1, 6, 8, 1, 10, 6, 1, 10, 6, 1, - 10, 6, 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, + 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, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 11, 0, 3, 3, 3, 5, - 3, 2, 1, 1, 4, 1, 4, 1, 4, 1, - 4, 1, 9, 0, 3, 3, 3, 2, 1, 19, - 1, 1, 1, 1, 0, 6, 3, 2, 1, 1, - 9, 1, 9, 1, 1, 0, 3, 3, 2, 1, - 7 + 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 }; diff --git a/src/wkt2_generated_parser.h b/src/wkt2_generated_parser.h index baeb0b4f..80b0c34b 100644 --- a/src/wkt2_generated_parser.h +++ b/src/wkt2_generated_parser.h @@ -121,76 +121,77 @@ extern int pj_wkt2_debug; T_COORDEPOCH = 330, T_COORDINATEMETADATA = 331, T_POINTMOTIONOPERATION = 332, - T_GEODETICCRS = 333, - T_GEODETICDATUM = 334, - T_PROJECTEDCRS = 335, - T_PRIMEMERIDIAN = 336, - T_GEOGRAPHICCRS = 337, - T_TRF = 338, - T_VERTICALCRS = 339, - T_VERTICALDATUM = 340, - T_VRF = 341, - T_TIMEDATUM = 342, - T_TEMPORALQUANTITY = 343, - T_ENGINEERINGDATUM = 344, - T_ENGINEERINGCRS = 345, - T_PARAMETRICDATUM = 346, - T_AFFINE = 347, - T_CARTESIAN = 348, - T_CYLINDRICAL = 349, - T_ELLIPSOIDAL = 350, - T_LINEAR = 351, - T_PARAMETRIC = 352, - T_POLAR = 353, - T_SPHERICAL = 354, - T_VERTICAL = 355, - T_TEMPORAL = 356, - T_TEMPORALCOUNT = 357, - T_TEMPORALMEASURE = 358, - T_ORDINAL = 359, - T_TEMPORALDATETIME = 360, - T_NORTH = 361, - T_NORTHNORTHEAST = 362, - T_NORTHEAST = 363, - T_EASTNORTHEAST = 364, - T_EAST = 365, - T_EASTSOUTHEAST = 366, - T_SOUTHEAST = 367, - T_SOUTHSOUTHEAST = 368, - T_SOUTH = 369, - T_SOUTHSOUTHWEST = 370, - T_SOUTHWEST = 371, - T_WESTSOUTHWEST = 372, - T_WEST = 373, - T_WESTNORTHWEST = 374, - T_NORTHWEST = 375, - T_NORTHNORTHWEST = 376, - T_UP = 377, - T_DOWN = 378, - T_GEOCENTRICX = 379, - T_GEOCENTRICY = 380, - T_GEOCENTRICZ = 381, - T_COLUMNPOSITIVE = 382, - T_COLUMNNEGATIVE = 383, - T_ROWPOSITIVE = 384, - T_ROWNEGATIVE = 385, - T_DISPLAYRIGHT = 386, - T_DISPLAYLEFT = 387, - T_DISPLAYUP = 388, - T_DISPLAYDOWN = 389, - T_FORWARD = 390, - T_AFT = 391, - T_PORT = 392, - T_STARBOARD = 393, - T_CLOCKWISE = 394, - T_COUNTERCLOCKWISE = 395, - T_TOWARDS = 396, - T_AWAYFROM = 397, - T_FUTURE = 398, - T_PAST = 399, - T_UNSPECIFIED = 400, - T_STRING = 401, - T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE = 402 + T_VERSION = 333, + T_GEODETICCRS = 334, + T_GEODETICDATUM = 335, + T_PROJECTEDCRS = 336, + T_PRIMEMERIDIAN = 337, + T_GEOGRAPHICCRS = 338, + T_TRF = 339, + T_VERTICALCRS = 340, + T_VERTICALDATUM = 341, + T_VRF = 342, + T_TIMEDATUM = 343, + T_TEMPORALQUANTITY = 344, + T_ENGINEERINGDATUM = 345, + T_ENGINEERINGCRS = 346, + T_PARAMETRICDATUM = 347, + T_AFFINE = 348, + T_CARTESIAN = 349, + T_CYLINDRICAL = 350, + T_ELLIPSOIDAL = 351, + T_LINEAR = 352, + T_PARAMETRIC = 353, + T_POLAR = 354, + T_SPHERICAL = 355, + T_VERTICAL = 356, + T_TEMPORAL = 357, + T_TEMPORALCOUNT = 358, + T_TEMPORALMEASURE = 359, + T_ORDINAL = 360, + T_TEMPORALDATETIME = 361, + T_NORTH = 362, + T_NORTHNORTHEAST = 363, + T_NORTHEAST = 364, + T_EASTNORTHEAST = 365, + T_EAST = 366, + T_EASTSOUTHEAST = 367, + T_SOUTHEAST = 368, + T_SOUTHSOUTHEAST = 369, + T_SOUTH = 370, + T_SOUTHSOUTHWEST = 371, + T_SOUTHWEST = 372, + T_WESTSOUTHWEST = 373, + T_WEST = 374, + T_WESTNORTHWEST = 375, + T_NORTHWEST = 376, + T_NORTHNORTHWEST = 377, + T_UP = 378, + T_DOWN = 379, + T_GEOCENTRICX = 380, + T_GEOCENTRICY = 381, + T_GEOCENTRICZ = 382, + T_COLUMNPOSITIVE = 383, + T_COLUMNNEGATIVE = 384, + T_ROWPOSITIVE = 385, + T_ROWNEGATIVE = 386, + T_DISPLAYRIGHT = 387, + T_DISPLAYLEFT = 388, + T_DISPLAYUP = 389, + T_DISPLAYDOWN = 390, + T_FORWARD = 391, + T_AFT = 392, + T_PORT = 393, + T_STARBOARD = 394, + T_CLOCKWISE = 395, + T_COUNTERCLOCKWISE = 396, + T_TOWARDS = 397, + T_AWAYFROM = 398, + T_FUTURE = 399, + T_PAST = 400, + T_UNSPECIFIED = 401, + T_STRING = 402, + T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE = 403 }; #endif diff --git a/src/wkt2_grammar.y b/src/wkt2_grammar.y index dddb0b30..6773d1e1 100644 --- a/src/wkt2_grammar.y +++ b/src/wkt2_grammar.y @@ -115,6 +115,7 @@ %token T_COORDEPOCH "COORDEPOCH" %token T_COORDINATEMETADATA "COORDINATEMETADATA" %token T_POINTMOTIONOPERATION "POINTMOTIONOPERATION" +%token T_VERSION "VERSION" /* WKT2 alternate (longer or shorter) */ %token T_GEODETICCRS "GEODETICCRS"; @@ -993,29 +994,30 @@ base_geodetic_crs: base_static_geodetic_crs | base_dynamic_geodetic_crs | base_static_geodetic_crs: base_geodetic_crs_keyword left_delimiter base_crs_name wkt_separator geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm - opt_separator_pm_ellipsoidal_cs_unit + opt_separator_pm_ellipsoidal_cs_unit_opt_separator_identifier_list right_delimiter -opt_separator_pm_ellipsoidal_cs_unit: - | wkt_separator prime_meridian - | wkt_separator prime_meridian wkt_separator ellipsoidal_cs_unit - | wkt_separator ellipsoidal_cs_unit +opt_separator_pm_ellipsoidal_cs_unit_opt_separator_identifier_list: + | wkt_separator prime_meridian opt_separator_identifier_list + | wkt_separator prime_meridian wkt_separator ellipsoidal_cs_unit opt_separator_identifier_list + | wkt_separator ellipsoidal_cs_unit opt_separator_identifier_list + | wkt_separator identifier opt_separator_identifier_list base_dynamic_geodetic_crs: base_geodetic_crs_keyword left_delimiter base_crs_name wkt_separator dynamic_crs wkt_separator geodetic_reference_frame_without_pm - opt_separator_pm_ellipsoidal_cs_unit + opt_separator_pm_ellipsoidal_cs_unit_opt_separator_identifier_list right_delimiter base_static_geographic_crs: base_geographic_crs_keyword left_delimiter base_crs_name wkt_separator geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm - opt_separator_pm_ellipsoidal_cs_unit + opt_separator_pm_ellipsoidal_cs_unit_opt_separator_identifier_list right_delimiter base_dynamic_geographic_crs: base_geographic_crs_keyword left_delimiter base_crs_name wkt_separator dynamic_crs wkt_separator geodetic_reference_frame_without_pm - opt_separator_pm_ellipsoidal_cs_unit + opt_separator_pm_ellipsoidal_cs_unit_opt_separator_identifier_list right_delimiter base_geodetic_crs_keyword: T_BASEGEODCRS @@ -1281,27 +1283,28 @@ derived_dynamic_geog_crs: geographic_crs_keyword base_static_geod_crs: base_geodetic_crs_keyword left_delimiter base_crs_name wkt_separator geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm - opt_separator_pm + opt_separator_pm_opt_separator_identifier_list right_delimiter -opt_separator_pm: - | wkt_separator prime_meridian +opt_separator_pm_opt_separator_identifier_list: + | wkt_separator prime_meridian opt_separator_identifier_list + | wkt_separator identifier opt_separator_identifier_list base_dynamic_geod_crs: base_geodetic_crs_keyword left_delimiter base_crs_name wkt_separator dynamic_crs wkt_separator geodetic_reference_frame_without_pm - opt_separator_pm + opt_separator_pm_opt_separator_identifier_list right_delimiter base_static_geog_crs: base_geographic_crs_keyword left_delimiter base_crs_name wkt_separator geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm - opt_separator_pm + opt_separator_pm_opt_separator_identifier_list right_delimiter base_dynamic_geog_crs: base_geographic_crs_keyword left_delimiter base_crs_name wkt_separator dynamic_crs wkt_separator geodetic_reference_frame_without_pm - opt_separator_pm + opt_separator_pm_opt_separator_identifier_list right_delimiter // Derived projected CRS @@ -1319,6 +1322,7 @@ derived_crs_name: quoted_latin_text base_projected_crs: base_projected_crs_keyword left_delimiter base_crs_name wkt_separator base_geodetic_geographic_crs wkt_separator map_projection + opt_separator_identifier_list right_delimiter base_projected_crs_keyword: T_BASEPROJCRS @@ -1337,11 +1341,15 @@ derived_vertical_crs: vertical_crs_keyword left_delimiter crs_name base_vertical_crs: base_static_vertical_crs | base_dynamic_vertical_crs base_static_vertical_crs: base_vertical_crs_keyword left_delimiter base_crs_name - wkt_separator vertical_reference_frame right_delimiter + wkt_separator vertical_reference_frame + opt_separator_identifier_list + right_delimiter base_dynamic_vertical_crs: base_vertical_crs_keyword left_delimiter base_crs_name wkt_separator dynamic_crs - wkt_separator vertical_reference_frame right_delimiter + wkt_separator vertical_reference_frame + opt_separator_identifier_list + right_delimiter base_vertical_crs_keyword: T_BASEVERTCRS @@ -1355,7 +1363,9 @@ derived_engineering_crs: engineering_crs_keyword left_delimiter crs_name right_delimiter base_engineering_crs: base_engineering_crs_keyword left_delimiter base_crs_name - wkt_separator engineering_datum right_delimiter + wkt_separator engineering_datum + opt_separator_identifier_list + right_delimiter base_engineering_crs_keyword: T_BASEENGCRS @@ -1369,7 +1379,9 @@ derived_parametric_crs: parametric_crs_keyword left_delimiter crs_name right_delimiter base_parametric_crs: base_parametric_crs_keyword left_delimiter base_crs_name - wkt_separator parametric_datum right_delimiter + wkt_separator parametric_datum + opt_separator_identifier_list + right_delimiter base_parametric_crs_keyword: T_BASEPARAMCRS @@ -1383,7 +1395,9 @@ derived_temporal_crs: temporal_crs_keyword left_delimiter crs_name right_delimiter base_temporal_crs: base_temporal_crs_keyword left_delimiter base_crs_name - wkt_separator temporal_datum right_delimiter + wkt_separator temporal_datum + opt_separator_identifier_list + right_delimiter base_temporal_crs_keyword: T_BASETIMECRS @@ -1451,6 +1465,13 @@ dynamic_crs_coordinate_metadata: dynamic_geodetic_crs | dynamic_geographic_crs | // Coordinate operations coordinate_operation: operation_keyword left_delimiter operation_name + coordinate_operation_next + +coordinate_operation_next: + wkt_separator operation_version coordinate_operation_end + | coordinate_operation_end + +coordinate_operation_end: wkt_separator source_crs wkt_separator target_crs wkt_separator operation_method opt_parameter_or_parameter_file_list_opt_interpolation_crs_opt_operation_accuracy_opt_separator_scope_extent_identifier_remark @@ -1468,6 +1489,13 @@ operation_keyword: T_COORDINATEOPERATION operation_name: quoted_latin_text +operation_version: operation_version_keyword left_delimiter + operation_version_text right_delimiter + +operation_version_keyword: T_VERSION + +operation_version_text: quoted_latin_text + source_crs: source_crs_keyword left_delimiter crs right_delimiter source_crs_keyword: T_SOURCECRS @@ -1488,6 +1516,13 @@ operation_accuracy_keyword: T_OPERATIONACCURACY // Point motion operation point_motion_operation: point_motion_keyword left_delimiter operation_name + point_motion_operation_next + +point_motion_operation_next: + wkt_separator operation_version point_motion_operation_end + | point_motion_operation_end + +point_motion_operation_end: wkt_separator source_crs wkt_separator operation_method opt_parameter_or_parameter_file_list_opt_operation_accuracy_opt_separator_scope_extent_identifier_remark @@ -1506,6 +1541,13 @@ point_motion_keyword: T_POINTMOTIONOPERATION concatenated_operation: concatenated_operation_keyword left_delimiter operation_name + concatenated_operation_next + +concatenated_operation_next: + wkt_separator operation_version concatenated_operation_end + | concatenated_operation_end + +concatenated_operation_end: wkt_separator source_crs wkt_separator target_crs wkt_separator step_keyword left_delimiter step right_delimiter wkt_separator step_keyword left_delimiter step right_delimiter @@ -1535,8 +1577,16 @@ bound_crs: bound_crs_keyword left_delimiter bound_crs_keyword: T_BOUNDCRS abridged_coordinate_transformation: abridged_transformation_keyword left_delimiter - operation_name wkt_separator - operation_method wkt_separator + operation_name + abridged_coordinate_transformation_next + +abridged_coordinate_transformation_next: + wkt_separator operation_version abridged_coordinate_transformation_end + | abridged_coordinate_transformation_end + +abridged_coordinate_transformation_end: + wkt_separator operation_method + wkt_separator abridged_parameter_or_parameter_file opt_end_abridged_coordinate_transformation right_delimiter diff --git a/src/wkt2_parser.cpp b/src/wkt2_parser.cpp index f77c7ceb..921d6dd4 100644 --- a/src/wkt2_parser.cpp +++ b/src/wkt2_parser.cpp @@ -100,7 +100,7 @@ static const wkt2_tokens tokens[] = { PAIR(GEOGRAPHICCRS), PAIR(TRF), PAIR(VERTICALCRS), PAIR(VERTICALDATUM), PAIR(VRF), PAIR(TIMEDATUM), PAIR(TEMPORALQUANTITY), PAIR(ENGINEERINGDATUM), PAIR(ENGINEERINGCRS), PAIR(PARAMETRICDATUM), PAIR(EPOCH), PAIR(COORDEPOCH), - PAIR(COORDINATEMETADATA), PAIR(POINTMOTIONOPERATION), + PAIR(COORDINATEMETADATA), PAIR(POINTMOTIONOPERATION), PAIR(VERSION), // CS types PAIR(AFFINE), PAIR(CARTESIAN), PAIR(CYLINDRICAL), PAIR(ELLIPSOIDAL), |
