diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2018-11-21 22:55:53 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2018-11-21 23:22:36 +0100 |
| commit | 85a4e9149152dd97463651496854f9ecbd720b84 (patch) | |
| tree | 8056ff79c1ae87bba92ed01d8435faf26a2ed230 /test/unit | |
| parent | fe59ae44f86b20c8ad85a699ae923a67b894c124 (diff) | |
| download | PROJ-85a4e9149152dd97463651496854f9ecbd720b84.tar.gz PROJ-85a4e9149152dd97463651496854f9ecbd720b84.zip | |
Move 'builtins' test of src/gie.c to test/unit/gie_self_tests.cpp
Diffstat (limited to 'test/unit')
| -rw-r--r-- | test/unit/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | test/unit/Makefile.am | 16 | ||||
| -rw-r--r-- | test/unit/gie_self_tests.cpp | 562 |
3 files changed, 580 insertions, 6 deletions
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 5138dafc..8a25d7a3 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -103,3 +103,11 @@ target_link_libraries(proj_test_cpp_api ${PROJ_LIBRARIES} ${SQLITE3_LIBRARY}) add_test(NAME proj_test_cpp_api COMMAND proj_test_cpp_api) + +add_executable(gie_self_tests + main.cpp + gie_self_tests.cpp) +target_link_libraries(gie_self_tests + gtest + ${PROJ_LIBRARIES}) +add_test(NAME gie_self_tests COMMAND gie_self_tests) diff --git a/test/unit/Makefile.am b/test/unit/Makefile.am index 77525f9a..913a3f29 100644 --- a/test/unit/Makefile.am +++ b/test/unit/Makefile.am @@ -13,13 +13,11 @@ noinst_PROGRAMS = basic_test noinst_PROGRAMS += pj_phi2_test noinst_PROGRAMS += proj_errno_string_test noinst_PROGRAMS += test_cpp_api +noinst_PROGRAMS += gie_self_tests basic_test_SOURCES = basic_test.cpp main.cpp basic_test_LDADD = ../../src/libproj.la ../../test/googletest/libgtest.la -test_cpp_api_SOURCES = test_util.cpp test_common.cpp test_crs.cpp test_metadata.cpp test_io.cpp test_operation.cpp test_datum.cpp test_factory.cpp test_c_api.cpp main.cpp -test_cpp_api_LDADD = ../../src/libproj.la ../../test/googletest/libgtest.la @SQLITE3_LDFLAGS@ - basic_test-check: basic_test ./basic_test @@ -35,10 +33,16 @@ proj_errno_string_test_LDADD= ../../src/libproj.la ../../test/googletest/libgtes proj_errno_string_test-check: proj_errno_string_test ./proj_errno_string_test -check-local: basic_test-check -check-local: pj_phi2_test-check proj_errno_string_test-check +test_cpp_api_SOURCES = test_util.cpp test_common.cpp test_crs.cpp test_metadata.cpp test_io.cpp test_operation.cpp test_datum.cpp test_factory.cpp test_c_api.cpp main.cpp +test_cpp_api_LDADD = ../../src/libproj.la ../../test/googletest/libgtest.la @SQLITE3_LDFLAGS@ test_cpp_api-check: test_cpp_api PROJ_LIB=$(PROJ_LIB) ./test_cpp_api -check-local: basic_test-check test_cpp_api-check +gie_self_tests_SOURCES = gie_self_tests.cpp main.cpp +gie_self_tests_LDADD = ../../src/libproj.la ../../test/googletest/libgtest.la @SQLITE3_LDFLAGS@ + +gie_self_tests-check: gie_self_tests + PROJ_LIB=$(PROJ_LIB) ./gie_self_tests + +check-local: basic_test-check pj_phi2_test-check proj_errno_string_test-check test_cpp_api-check gie_self_tests-check diff --git a/test/unit/gie_self_tests.cpp b/test/unit/gie_self_tests.cpp new file mode 100644 index 00000000..67a44fe5 --- /dev/null +++ b/test/unit/gie_self_tests.cpp @@ -0,0 +1,562 @@ +/****************************************************************************** + * + * Project: PROJ + * Purpose: Test + * Author: Even Rouault <even dot rouault at spatialys dot com> + * + ****************************************************************************** + * Copyright (c) 2017, Thomas Knudsen + * Copyright (c) 2017, SDFE + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include "gtest_include.h" + +// PROJ include order is sensitive +// clang-format off +#include "proj_internal.h" +#include "proj.h" +#include "projects.h" +// clang-format on + +#include <cmath> +#include <string> + +namespace { + +// --------------------------------------------------------------------------- + +TEST( gie, cart_selftest ) { + PJ_CONTEXT *ctx; + PJ *P; + PJ_COORD a, b, obs[2]; + PJ_COORD coord[2]; + + PJ_INFO info; + PJ_PROJ_INFO pj_info; + PJ_GRID_INFO grid_info; + PJ_INIT_INFO init_info; + + PJ_FACTORS factors; + + const PJ_OPERATIONS *oper_list; + const PJ_ELLPS *ellps_list; + const PJ_UNITS *unit_list; + const PJ_PRIME_MERIDIANS *pm_list; + + int err; + size_t n, sz; + double dist, h, t; + const char * const args[3] = {"proj=utm", "zone=32", "ellps=GRS80"}; + char arg[50] = {"+proj=utm; +zone=32; +ellps=GRS80"}; + char buf[40]; + + /* An utm projection on the GRS80 ellipsoid */ + P = proj_create (PJ_DEFAULT_CTX, arg); + ASSERT_TRUE( P != nullptr ); + + /* Clean up */ + proj_destroy (P); + + /* Same projection, now using argc/argv style initialization */ + P = proj_create_argv (PJ_DEFAULT_CTX, 3, const_cast<char**>(args)); + ASSERT_TRUE( P != nullptr ); + + /* zero initialize everything, then set (longitude, latitude) to (12, 55) */ + a = proj_coord (0,0,0,0); + /* a.lp: The coordinate part of a, interpreted as a classic LP pair */ + a.lp.lam = proj_torad(12); + a.lp.phi = proj_torad(55); + + /* Forward projection */ + b = proj_trans (P, PJ_FWD, a); + + /* Inverse projection */ + a = proj_trans (P, PJ_INV, b); + + /* Null projection */ + a = proj_trans (P, PJ_IDENT, a); + + /* Forward again, to get two linear items for comparison */ + a = proj_trans (P, PJ_FWD, a); + + dist = proj_xy_dist (a, b); + ASSERT_LE(dist, 2e-9); + + /* Clear any previous error */ + proj_errno_reset (P); + + /* Invalid projection */ + a = proj_trans (P, static_cast<PJ_DIRECTION>(42), a); + ASSERT_EQ(a.lpz.lam, HUGE_VAL); + + err = proj_errno (P); + ASSERT_NE(err, 0); + + /* Clear error again */ + proj_errno_reset (P); + + /* Clean up */ + proj_destroy (P); + + /* Now do some 3D transformations */ + P = proj_create (PJ_DEFAULT_CTX, "+proj=cart +ellps=GRS80"); + ASSERT_TRUE( P != nullptr ); + + /* zero initialize everything, then set (longitude, latitude, height) to (12, 55, 100) */ + a = b = proj_coord (0,0,0,0); + a.lpz.lam = proj_torad(12); + a.lpz.phi = proj_torad(55); + a.lpz.z = 100; + + /* Forward projection: 3D-Cartesian-to-Ellipsoidal */ + b = proj_trans (P, PJ_FWD, a); + + /* Check roundtrip precision for 10000 iterations each way */ + dist = proj_roundtrip (P, PJ_FWD, 10000, &a); + dist += proj_roundtrip (P, PJ_INV, 10000, &b); + ASSERT_LE(dist, 4e-9); + + + /* Test at the North Pole */ + a = b = proj_coord (0,0,0,0); + a.lpz.lam = proj_torad(0); + a.lpz.phi = proj_torad(90); + a.lpz.z = 100; + + /* Forward projection: Ellipsoidal-to-3D-Cartesian */ + dist = proj_roundtrip (P, PJ_FWD, 1, &a); + ASSERT_LE(dist, 1e-9); + + /* Test at the South Pole */ + a = b = proj_coord (0,0,0,0); + a.lpz.lam = proj_torad(0); + a.lpz.phi = proj_torad(-90); + a.lpz.z = 100; + b = a; + + /* Forward projection: Ellipsoidal-to-3D-Cartesian */ + dist = proj_roundtrip (P, PJ_FWD, 1, &a); + ASSERT_LE(dist, 4e-9); + + /* Inverse projection: 3D-Cartesian-to-Ellipsoidal */ + b = proj_trans (P, PJ_INV, b); + + /* Move p to another context */ + ctx = proj_context_create (); + ASSERT_NE (ctx, pj_get_default_ctx()); + + proj_context_set (P, ctx); + ASSERT_EQ (ctx, P->ctx); + + b = proj_trans (P, PJ_FWD, b); + + /* Move it back to the default context */ + proj_context_set (P, 0); + ASSERT_EQ (pj_get_default_ctx(), P->ctx); + + proj_context_destroy (ctx); + + /* We go on with the work - now back on the default context */ + b = proj_trans (P, PJ_INV, b); + proj_destroy (P); + + + /* Testing proj_trans_generic () */ + + /* An utm projection on the GRS80 ellipsoid */ + P = proj_create (PJ_DEFAULT_CTX, "+proj=utm +zone=32 +ellps=GRS80"); + ASSERT_TRUE( P != nullptr ); + + obs[0] = proj_coord (proj_torad(12), proj_torad(55), 45, 0); + obs[1] = proj_coord (proj_torad(12), proj_torad(56), 50, 0); + sz = sizeof (PJ_COORD); + + /* Forward projection */ + a = proj_trans (P, PJ_FWD, obs[0]); + b = proj_trans (P, PJ_FWD, obs[1]); + + n = proj_trans_generic ( + P, PJ_FWD, + &(obs[0].lpz.lam), sz, 2, + &(obs[0].lpz.phi), sz, 2, + &(obs[0].lpz.z), sz, 2, + 0, sz, 0 + ); + ASSERT_EQ(n, 2); + + ASSERT_EQ (a.lpz.lam , obs[0].lpz.lam); + ASSERT_EQ (a.lpz.phi , obs[0].lpz.phi); + ASSERT_EQ (a.lpz.z , obs[0].lpz.z); + ASSERT_EQ (b.lpz.lam , obs[1].lpz.lam); + ASSERT_EQ (b.lpz.phi , obs[1].lpz.phi); + ASSERT_EQ (b.lpz.z , obs[1].lpz.z); + + /* now test the case of constant z */ + obs[0] = proj_coord (proj_torad(12), proj_torad(55), 45, 0); + obs[1] = proj_coord (proj_torad(12), proj_torad(56), 50, 0); + h = 27; + t = 33; + n = proj_trans_generic ( + P, PJ_FWD, + &(obs[0].lpz.lam), sz, 2, + &(obs[0].lpz.phi), sz, 2, + &h, 0, 1, + &t, 0, 1 + ); + ASSERT_EQ(n, 2); + + ASSERT_EQ (a.lpz.lam , obs[0].lpz.lam); + ASSERT_EQ (a.lpz.phi , obs[0].lpz.phi); + ASSERT_EQ (45, obs[0].lpz.z); + ASSERT_EQ (b.lpz.lam, obs[1].lpz.lam); + ASSERT_EQ (b.lpz.phi, obs[1].lpz.phi); + ASSERT_EQ (50, obs[1].lpz.z); + ASSERT_NE (50, h); + + /* test proj_trans_array () */ + + coord[0] = proj_coord (proj_torad(12), proj_torad(55), 45, 0); + coord[1] = proj_coord (proj_torad(12), proj_torad(56), 50, 0); + ASSERT_FALSE (proj_trans_array (P, PJ_FWD, 2, coord)); + + ASSERT_EQ (a.lpz.lam , coord[0].lpz.lam); + ASSERT_EQ (a.lpz.phi , coord[0].lpz.phi); + ASSERT_EQ (a.lpz.z , coord[0].lpz.z); + ASSERT_EQ (b.lpz.lam , coord[1].lpz.lam); + ASSERT_EQ (b.lpz.phi , coord[1].lpz.phi); + ASSERT_EQ (b.lpz.z , coord[1].lpz.z); + + /* Clean up after proj_trans_* tests */ + proj_destroy (P); + + /* test proj_create_crs_to_crs() */ + P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, "epsg:25832", "epsg:25833", NULL); + ASSERT_TRUE( P != nullptr ); + + a.xy.x = 700000.0; + a.xy.y = 6000000.0; + b.xy.x = 307788.8761171057; + b.xy.y = 5999669.3036037628; + + a = proj_trans(P, PJ_FWD, a); + ASSERT_LE(dist, 1e-7); + proj_destroy(P); + + /* let's make sure that only entries in init-files results in a usable PJ */ + P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, "proj=utm +zone=32 +datum=WGS84", "proj=utm +zone=33 +datum=WGS84", NULL); + ASSERT_TRUE( P == nullptr ); + proj_destroy(P); + + /* ********************************************************************** */ + /* Test info functions */ + /* ********************************************************************** */ + + /* proj_info() */ + /* this one is difficult to test, since the output changes with the setup */ + info = proj_info(); + + if (info.version[0] != '\0' ) { + char tmpstr[64]; + sprintf(tmpstr, "%d.%d.%d", info.major, info.minor, info.patch); + ASSERT_EQ( std::string(info.version), std::string(tmpstr) ); + } + ASSERT_NE( std::string(info.release), "" ); + if (getenv ("HOME") || getenv ("PROJ_LIB")) { + ASSERT_NE( std::string(info.searchpath), std::string() ); + } + + /* proj_pj_info() */ + { + P = proj_create(PJ_DEFAULT_CTX, "+proj=august"); /* august has no inverse */ + auto has_inverse = proj_pj_info(P).has_inverse; + proj_destroy(P); + ASSERT_FALSE(has_inverse); + } + + P = proj_create(PJ_DEFAULT_CTX, arg); + pj_info = proj_pj_info(P); + ASSERT_TRUE( pj_info.has_inverse ); + pj_shrink (arg); + ASSERT_EQ( std::string(pj_info.definition), arg ); + ASSERT_EQ( std::string(pj_info.id), "utm" ); + + proj_destroy(P); + + /* proj_grid_info() */ + grid_info = proj_grid_info("null"); + ASSERT_NE( std::string(grid_info.filename), "" ); + ASSERT_EQ( std::string(grid_info.gridname), "null" ); + + grid_info = proj_grid_info("nonexistinggrid"); + ASSERT_EQ( std::string(grid_info.filename), "" ); + + /* proj_init_info() */ + init_info = proj_init_info("unknowninit"); + ASSERT_EQ( std::string(init_info.filename), "" ); + + init_info = proj_init_info("epsg"); + /* Need to allow for "Unknown" until all commonly distributed EPSG-files comes with a metadata section */ + ASSERT_TRUE( std::string(init_info.origin) == "EPSG" || std::string(init_info.origin) == "Unknown" ) << std::string(init_info.origin); + ASSERT_EQ( std::string(init_info.name), "epsg" ); + + + /* test proj_rtodms() and proj_dmstor() */ + ASSERT_EQ( std::string("180dN"), proj_rtodms(buf, M_PI, 'N', 'S')); + + ASSERT_EQ(proj_dmstor(&buf[0], NULL), M_PI); + + ASSERT_EQ( std::string("114d35'29.612\"S"), proj_rtodms(buf, -2.0, 'N', 'S')); + + /* we can't expect perfect numerical accuracy so testing with a tolerance */ + ASSERT_NEAR (-2.0 , proj_dmstor(&buf[0], NULL) , 1e-7); + + /* test proj_derivatives_retrieve() and proj_factors_retrieve() */ + P = proj_create(PJ_DEFAULT_CTX, "+proj=merc"); + a = proj_coord (0,0,0,0); + a.lp.lam = proj_torad(12); + a.lp.phi = proj_torad(55); + + factors = proj_factors(P, a); + ASSERT_FALSE (proj_errno(P)); /* factors not created correctly */ + + /* check a few key characteristics of the Mercator projection */ + ASSERT_EQ (factors.angular_distortion, 0.0); /* angular distortion should be 0 */ + ASSERT_EQ (factors.meridian_parallel_angle, M_PI_2); /* Meridian/parallel angle should be 90 deg */ + ASSERT_EQ (factors.meridian_convergence, 0.0); /* meridian convergence should be 0 */ + + proj_destroy(P); + + /* Check that proj_list_* functions work by looping through them */ + n = 0; + for (oper_list = proj_list_operations(); oper_list->id; ++oper_list) n++; + ASSERT_NE(n, 0U); + + n = 0; + for (ellps_list = proj_list_ellps(); ellps_list->id; ++ellps_list) n++; + ASSERT_NE(n, 0U); + + n = 0; + for (unit_list = proj_list_units(); unit_list->id; ++unit_list) n++; + ASSERT_NE(n, 0U); + + n = 0; + for (pm_list = proj_list_prime_meridians(); pm_list->id; ++pm_list) n++; + ASSERT_NE(n, 0U); + + + /* check io-predicates */ + + /* angular in on fwd, linear out */ + P = proj_create (PJ_DEFAULT_CTX, "+proj=cart +ellps=GRS80"); + ASSERT_TRUE( P != nullptr ); + ASSERT_TRUE(proj_angular_input (P, PJ_FWD)); + ASSERT_FALSE(proj_angular_input (P, PJ_INV)); + ASSERT_FALSE(proj_angular_output (P, PJ_FWD)); + ASSERT_TRUE(proj_angular_output (P, PJ_INV)); + P->inverted = 1; + ASSERT_FALSE(proj_angular_input (P, PJ_FWD)); + ASSERT_TRUE(proj_angular_input (P, PJ_INV)); + ASSERT_TRUE(proj_angular_output (P, PJ_FWD)); + ASSERT_FALSE(proj_angular_output (P, PJ_INV)); + proj_destroy(P); + + /* angular in and out */ + P = proj_create(PJ_DEFAULT_CTX, + "+proj=molodensky +a=6378160 +rf=298.25 " + "+da=-23 +df=-8.120449e-8 +dx=-134 +dy=-48 +dz=149 " + "+abridged " + ); + ASSERT_TRUE( P != nullptr ); + ASSERT_TRUE(proj_angular_input (P, PJ_FWD)); + ASSERT_TRUE(proj_angular_input (P, PJ_INV)); + ASSERT_TRUE(proj_angular_output (P, PJ_FWD)); + ASSERT_TRUE(proj_angular_output (P, PJ_INV)); + P->inverted = 1; + ASSERT_TRUE(proj_angular_input (P, PJ_FWD)); + ASSERT_TRUE(proj_angular_input (P, PJ_INV)); + ASSERT_TRUE(proj_angular_output (P, PJ_FWD)); + ASSERT_TRUE(proj_angular_output (P, PJ_INV)); + proj_destroy(P); + + /* linear in and out */ + P = proj_create(PJ_DEFAULT_CTX, + " +proj=helmert" + " +x=0.0127 +y=0.0065 +z=-0.0209 +s=0.00195" + " +rx=-0.00039 +ry=0.00080 +rz=-0.00114" + " +dx=-0.0029 +dy=-0.0002 +dz=-0.0006 +ds=0.00001" + " +drx=-0.00011 +dry=-0.00019 +drz=0.00007" + " +t_epoch=1988.0 +convention=coordinate_frame +no_defs" + ); + ASSERT_TRUE( P != nullptr ); + ASSERT_FALSE(proj_angular_input (P, PJ_FWD)); + ASSERT_FALSE(proj_angular_input (P, PJ_INV)); + ASSERT_FALSE(proj_angular_output (P, PJ_FWD)); + ASSERT_FALSE(proj_angular_output (P, PJ_INV)); + P->inverted = 1; + ASSERT_FALSE(proj_angular_input (P, PJ_FWD)); + ASSERT_FALSE(proj_angular_input (P, PJ_INV)); + ASSERT_FALSE(proj_angular_output (P, PJ_FWD)); + ASSERT_FALSE(proj_angular_output (P, PJ_INV)); + + /* We specified "no_defs" but didn't give any ellipsoid info */ + /* pj_init_ctx should default to WGS84 */ + ASSERT_EQ (P->a, 6378137.0); + ASSERT_EQ (P->f, 1.0/298.257223563); + proj_destroy(P); + + /* Test that pj_fwd* and pj_inv* returns NaNs when receiving NaN input */ + P = proj_create(PJ_DEFAULT_CTX, "+proj=merc"); + ASSERT_TRUE( P != nullptr ); + a = proj_coord(NAN, NAN, NAN, NAN); + a = proj_trans(P, PJ_FWD, a); + ASSERT_TRUE ( ( std::isnan(a.v[0]) && std::isnan(a.v[1]) && std::isnan(a.v[2]) && std::isnan(a.v[3]) ) ); + + a = proj_coord(NAN, NAN, NAN, NAN); + a = proj_trans(P, PJ_INV, a); + ASSERT_TRUE ( ( std::isnan(a.v[0]) && std::isnan(a.v[1]) && std::isnan(a.v[2]) && std::isnan(a.v[3]) ) ); + proj_destroy(P); + +} + +// --------------------------------------------------------------------------- + +static void test_time(const char* args, double tol, double t_in, double t_exp) { + PJ_COORD in, out; + PJ *P = proj_create(PJ_DEFAULT_CTX, args); + + ASSERT_TRUE(P != 0); + + in = proj_coord(0.0, 0.0, 0.0, t_in); + + out = proj_trans(P, PJ_FWD, in); + EXPECT_NEAR(out.xyzt.t, t_exp, tol); + + out = proj_trans(P, PJ_INV, out); + EXPECT_NEAR(out.xyzt.t, t_in, tol); + + pj_free(P); + + proj_log_level(NULL, PJ_LOG_NONE); +} + +// --------------------------------------------------------------------------- + +TEST( gie, unitconvert_selftest ) { + + char args1[] = "+proj=unitconvert +t_in=decimalyear +t_out=decimalyear"; + double in1 = 2004.25; + + char args2[] = "+proj=unitconvert +t_in=gps_week +t_out=gps_week"; + double in2 = 1782.0; + + char args3[] = "+proj=unitconvert +t_in=mjd +t_out=mjd"; + double in3 = 57390.0; + + char args4[] = "+proj=unitconvert +t_in=gps_week +t_out=decimalyear"; + double in4 = 1877.71428, exp4 = 2016.0; + + char args5[] = "+proj=unitconvert +t_in=yyyymmdd +t_out=yyyymmdd"; + double in5 = 20170131; + + test_time(args1, 1e-6, in1, in1); + test_time(args2, 1e-6, in2, in2); + test_time(args3, 1e-6, in3, in3); + test_time(args4, 1e-6, in4, exp4); + test_time(args5, 1e-6, in5, in5); +} + + +static const char tc32_utm32[] = { + " +proj=horner" + " +ellps=intl" + " +range=500000" + " +fwd_origin=877605.269066,6125810.306769" + " +inv_origin=877605.760036,6125811.281773" + " +deg=4" + " +fwd_v=6.1258112678e+06,9.9999971567e-01,1.5372750011e-10,5.9300860915e-15,2.2609497633e-19,4.3188227445e-05,2.8225130416e-10,7.8740007114e-16,-1.7453997279e-19,1.6877465415e-10,-1.1234649773e-14,-1.7042333358e-18,-7.9303467953e-15,-5.2906832535e-19,3.9984284847e-19" + " +fwd_u=8.7760574982e+05,9.9999752475e-01,2.8817299305e-10,5.5641310680e-15,-1.5544700949e-18,-4.1357045890e-05,4.2106213519e-11,2.8525551629e-14,-1.9107771273e-18,3.3615590093e-10,2.4380247154e-14,-2.0241230315e-18,1.2429019719e-15,5.3886155968e-19,-1.0167505000e-18" + " +inv_v=6.1258103208e+06,1.0000002826e+00,-1.5372762184e-10,-5.9304261011e-15,-2.2612705361e-19,-4.3188331419e-05,-2.8225549995e-10,-7.8529116371e-16,1.7476576773e-19,-1.6875687989e-10,1.1236475299e-14,1.7042518057e-18,7.9300735257e-15,5.2881862699e-19,-3.9990736798e-19" + " +inv_u=8.7760527928e+05,1.0000024735e+00,-2.8817540032e-10,-5.5627059451e-15,1.5543637570e-18,4.1357152105e-05,-4.2114813612e-11,-2.8523713454e-14,1.9109017837e-18,-3.3616407783e-10,-2.4382678126e-14,2.0245020199e-18,-1.2441377565e-15,-5.3885232238e-19,1.0167203661e-18" +}; + +static const char sb_utm32[] = { + " +proj=horner" + " +ellps=intl" + " +range=500000" + " +tolerance=0.0005" + " +fwd_origin=4.94690026817276e+05,6.13342113183056e+06" + " +inv_origin=6.19480258923588e+05,6.13258568148837e+06" + " +deg=3" + " +fwd_c=6.13258562111350e+06,6.19480105709997e+05,9.99378966275206e-01,-2.82153291753490e-02,-2.27089979140026e-10,-1.77019590701470e-09,1.08522286274070e-14,2.11430298751604e-15" + " +inv_c=6.13342118787027e+06,4.94690181709311e+05,9.99824464710368e-01,2.82279070814774e-02,7.66123542220864e-11,1.78425334628927e-09,-1.05584823306400e-14,-3.32554258683744e-15" +}; + +// --------------------------------------------------------------------------- + +TEST( gie, horner_selftest ) { + + PJ *P; + PJ_COORD a, b, c; + double dist; + + /* Real polynonia relating the technical coordinate system TC32 to "System 45 Bornholm" */ + P = proj_create (PJ_DEFAULT_CTX, tc32_utm32); + ASSERT_TRUE( P != nullptr ); + + a = b = proj_coord (0,0,0,0); + a.uv.v = 6125305.4245; + a.uv.u = 878354.8539; + c = a; + + /* Check roundtrip precision for 1 iteration each way, starting in forward direction */ + dist = proj_roundtrip (P, PJ_FWD, 1, &c); + EXPECT_LE( dist, 0.01 ); + proj_destroy(P); + + /* The complex polynomial transformation between the "System Storebaelt" and utm32/ed50 */ + P = proj_create (PJ_DEFAULT_CTX, sb_utm32); + ASSERT_TRUE( P != nullptr ); + + /* Test value: utm32_ed50(620000, 6130000) = sb_ed50(495136.8544, 6130821.2945) */ + a = b = c = proj_coord (0,0,0,0); + a.uv.v = 6130821.2945; + a.uv.u = 495136.8544; + c.uv.v = 6130000.0000; + c.uv.u = 620000.0000; + + /* Forward projection */ + b = proj_trans (P, PJ_FWD, a); + dist = proj_xy_dist (b, c); + EXPECT_LE( dist, 0.001 ); + + /* Inverse projection */ + b = proj_trans (P, PJ_INV, c); + dist = proj_xy_dist (b, a); + EXPECT_LE( dist, 0.001 ); + + /* Check roundtrip precision for 1 iteration each way */ + dist = proj_roundtrip (P, PJ_FWD, 1, &a); + EXPECT_LE( dist, 0.01 ); + + proj_destroy(P); +} + +} // namespace |
