aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2018-11-21 22:55:53 +0100
committerEven Rouault <even.rouault@spatialys.com>2018-11-21 23:22:36 +0100
commit85a4e9149152dd97463651496854f9ecbd720b84 (patch)
tree8056ff79c1ae87bba92ed01d8435faf26a2ed230
parentfe59ae44f86b20c8ad85a699ae923a67b894c124 (diff)
downloadPROJ-85a4e9149152dd97463651496854f9ecbd720b84.tar.gz
PROJ-85a4e9149152dd97463651496854f9ecbd720b84.zip
Move 'builtins' test of src/gie.c to test/unit/gie_self_tests.cpp
-rw-r--r--src/gie.c632
-rw-r--r--test/gie/more_builtins.gie7
-rw-r--r--test/unit/CMakeLists.txt8
-rw-r--r--test/unit/Makefile.am16
-rw-r--r--test/unit/gie_self_tests.cpp562
5 files changed, 581 insertions, 644 deletions
diff --git a/src/gie.c b/src/gie.c
index 73b27df8..d71a3e75 100644
--- a/src/gie.c
+++ b/src/gie.c
@@ -149,7 +149,7 @@ static ffio *ffio_create (const char **tags, size_t n_tags, size_t max_record_si
static const char *gie_tags[] = {
"<gie>", "operation", "accept", "expect", "roundtrip", "banner", "verbose",
- "direction", "tolerance", "ignore", "require_grid", "builtins", "echo", "skip", "</gie>"
+ "direction", "tolerance", "ignore", "require_grid", "echo", "skip", "</gie>"
};
static const size_t n_gie_tags = sizeof gie_tags / sizeof gie_tags[0];
@@ -196,8 +196,6 @@ ffio *F = 0;
static gie_ctx T;
int tests=0, succs=0, succ_fails=0, fail_fails=0, succ_rtps=0, fail_rtps=0;
-int succ_builtins=0, fail_builtins=0;
-
static const char delim[] = {"-------------------------------------------------------------------------------\n"};
@@ -312,7 +310,6 @@ int main (int argc, char **argv) {
if (T.verbosity > 1) {
fprintf (T.fout, "Failing roundtrips: %4d, Succeeding roundtrips: %4d\n", fail_rtps, succ_rtps);
fprintf (T.fout, "Failing failures: %4d, Succeeding failures: %4d\n", fail_fails, succ_fails);
- fprintf (T.fout, "Failing builtins: %4d, Succeeding builtins: %4d\n", fail_builtins, succ_builtins);
fprintf (T.fout, "Internal counters: %4.4d(%4.4d)\n", tests, succs);
fprintf (T.fout, "%s", delim);
}
@@ -369,17 +366,6 @@ static int another_failing_roundtrip (void) {
return another_failure ();
}
-static int another_succeeding_builtin (void) {
- succ_builtins++;
- return another_success ();
-}
-
-static int another_failing_builtin (void) {
- fail_builtins++;
- return another_failure ();
-}
-
-
static int process_file (const char *fname) {
FILE *f;
@@ -606,57 +592,6 @@ either a conversion or a transformation)
return 0;
}
-
-
-
-static int unitconvert_selftest (void);
-static int cart_selftest (void);
-static int horner_selftest (void);
-
-/*****************************************************************************/
-static int builtins (const char *args) {
-/*****************************************************************************
-There are still a few tests that cannot be described using gie
-primitives. Instead, they are implemented as builtins, and invoked
-using the "builtins" command verb.
-******************************************************************************/
- int i;
- if (T.verbosity > 1) {
- finish_previous_operation (args);
- banner ("builtins: unitconvert, horner, cart");
- }
- T.op_ok = 0;
- T.op_ko = 0;
- T.op_skip = 0;
- i = unitconvert_selftest ();
- if (i!=0) {
- fprintf (T.fout, "unitconvert_selftest fails with %d\n", i);
- another_failing_builtin();
- }
- else
- another_succeeding_builtin ();
-
-
- i = cart_selftest ();
- if (i!=0) {
- fprintf (T.fout, "cart_selftest fails with %d\n", i);
- another_failing_builtin();
- }
- else
- another_succeeding_builtin ();
-
- i = horner_selftest ();
- if (i!=0) {
- fprintf (T.fout, "horner_selftest fails with %d\n", i);
- another_failing_builtin();
- }
- else
- another_succeeding_builtin ();
-
- return 0;
-}
-
-
static PJ_COORD torad_coord (PJ *P, PJ_DIRECTION dir, PJ_COORD a) {
size_t i, n;
char *axis = "enut";
@@ -1064,7 +999,6 @@ static int dispatch (const char *cmnd, const char *args) {
if (0==strcmp (cmnd, "tolerance")) return tolerance (args);
if (0==strcmp (cmnd, "ignore")) return ignore (args);
if (0==strcmp (cmnd, "require_grid")) return require_grid (args);
- if (0==strcmp (cmnd, "builtins")) return builtins (args);
if (0==strcmp (cmnd, "echo")) return echo (args);
if (0==strcmp (cmnd, "skip")) return skip (args);
@@ -1508,567 +1442,3 @@ whitespace etc. The block is stored in G->args. Returns 1 on success, 0 otherwis
pj_shrink (G->args);
return 1;
}
-
-
-
-
-
-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"
-};
-
-static int horner_selftest (void) {
- 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);
- if (0==P)
- return 10;
-
- 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);
- if (dist > 0.01)
- return 1;
- proj_destroy(P);
-
- /* The complex polynomial transformation between the "System Storebaelt" and utm32/ed50 */
- P = proj_create (PJ_DEFAULT_CTX, sb_utm32);
- if (0==P)
- return 11;
-
- /* 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);
- if (dist > 0.001)
- return 2;
-
- /* Inverse projection */
- b = proj_trans (P, PJ_INV, c);
- dist = proj_xy_dist (b, a);
- if (dist > 0.001)
- return 3;
-
- /* Check roundtrip precision for 1 iteration each way */
- dist = proj_roundtrip (P, PJ_FWD, 1, &a);
- if (dist > 0.01)
- return 4;
-
- proj_destroy(P);
- return 0;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-/* Testing quite a bit of the pj_obs_api as a side effect (inspired by pj_obs_api_test.c) */
-static int cart_selftest (void) {
- 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;
- char *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);
- if (0==P)
- return 1;
-
-
- /* Clean up */
- proj_destroy (P);
-
- /* Same projection, now using argc/argv style initialization */
- P = proj_create_argv (PJ_DEFAULT_CTX, 3, args);
- if (0==P)
- return 2;
-
- /* 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 = PJ_TORAD(12);
- a.lp.phi = PJ_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);
- if (dist > 2e-9)
- return 3;
-
- /* Clear any previous error */
- proj_errno_reset (P);
-
- /* Invalid projection */
- a = proj_trans (P, 42, a);
- if (a.lpz.lam!=HUGE_VAL)
- return 4;
- err = proj_errno (P);
- if (0==err)
- return 5;
-
- /* 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");
- if (0==P)
- return 6;
-
- /* zero initialize everything, then set (longitude, latitude, height) to (12, 55, 100) */
- a = b = proj_coord (0,0,0,0);
- a.lpz.lam = PJ_TORAD(12);
- a.lpz.phi = PJ_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);
- if (dist > 4e-9)
- return 7;
-
-
- /* Test at the North Pole */
- a = b = proj_coord (0,0,0,0);
- a.lpz.lam = PJ_TORAD(0);
- a.lpz.phi = PJ_TORAD(90);
- a.lpz.z = 100;
-
- /* Forward projection: Ellipsoidal-to-3D-Cartesian */
- dist = proj_roundtrip (P, PJ_FWD, 1, &a);
- if (dist > 1e-9)
- return 8;
-
- /* Test at the South Pole */
- a = b = proj_coord (0,0,0,0);
- a.lpz.lam = PJ_TORAD(0);
- a.lpz.phi = PJ_TORAD(-90);
- a.lpz.z = 100;
- b = a;
-
- /* Forward projection: Ellipsoidal-to-3D-Cartesian */
- dist = proj_roundtrip (P, PJ_FWD, 1, &a);
- if (dist > 1e-9)
- return 9;
-
-
- /* Inverse projection: 3D-Cartesian-to-Ellipsoidal */
- b = proj_trans (P, PJ_INV, b);
-
- /* Move p to another context */
- ctx = proj_context_create ();
- if (ctx==pj_get_default_ctx())
- return 10;
- proj_context_set (P, ctx);
- if (ctx != P->ctx)
- return 11;
- b = proj_trans (P, PJ_FWD, b);
-
- /* Move it back to the default context */
- proj_context_set (P, 0);
- if (pj_get_default_ctx() != P->ctx)
- return 12;
- 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");
- if (0==P)
- return 13;
-
- obs[0] = proj_coord (PJ_TORAD(12), PJ_TORAD(55), 45, 0);
- obs[1] = proj_coord (PJ_TORAD(12), PJ_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
- );
- if (2!=n)
- return 14;
- if (a.lpz.lam != obs[0].lpz.lam) return 15;
- if (a.lpz.phi != obs[0].lpz.phi) return 16;
- if (a.lpz.z != obs[0].lpz.z) return 17;
- if (b.lpz.lam != obs[1].lpz.lam) return 18;
- if (b.lpz.phi != obs[1].lpz.phi) return 19;
- if (b.lpz.z != obs[1].lpz.z) return 20;
-
- /* now test the case of constant z */
- obs[0] = proj_coord (PJ_TORAD(12), PJ_TORAD(55), 45, 0);
- obs[1] = proj_coord (PJ_TORAD(12), PJ_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
- );
- if (2!=n)
- return 21;
- if (a.lpz.lam != obs[0].lpz.lam) return 22;
- if (a.lpz.phi != obs[0].lpz.phi) return 23;
- if (45 != obs[0].lpz.z) return 24;
- if (b.lpz.lam != obs[1].lpz.lam) return 25;
- if (b.lpz.phi != obs[1].lpz.phi) return 26;
- if (50 != obs[1].lpz.z) return 27; /* NOTE: unchanged */
- if (50==h) return 28;
-
- /* test proj_trans_array () */
-
- coord[0] = proj_coord (PJ_TORAD(12), PJ_TORAD(55), 45, 0);
- coord[1] = proj_coord (PJ_TORAD(12), PJ_TORAD(56), 50, 0);
- if (proj_trans_array (P, PJ_FWD, 2, coord))
- return 40;
-
- if (a.lpz.lam != coord[0].lpz.lam) return 41;
- if (a.lpz.phi != coord[0].lpz.phi) return 42;
- if (a.lpz.z != coord[0].lpz.z) return 43;
- if (b.lpz.lam != coord[1].lpz.lam) return 44;
- if (b.lpz.phi != coord[1].lpz.phi) return 45;
- if (b.lpz.z != coord[1].lpz.z) return 46;
-
- /* 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);
- if (P==0)
- return 50;
-
- 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);
- if (dist > 1e-7)
- return 51;
- 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);
- if (P != 0) {
- proj_destroy(P);
- return 52;
- }
- 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);
- if (strcmp(info.version, tmpstr)) return 55;
- }
- if (info.release[0] == '\0') return 56;
- if (getenv ("HOME") || getenv ("PROJ_LIB"))
- if (info.searchpath[0] == '\0') return 57;
-
- /* proj_pj_info() */
- P = proj_create(PJ_DEFAULT_CTX, "+proj=august"); /* august has no inverse */
- if (proj_pj_info(P).has_inverse) { proj_destroy(P); return 60; }
- proj_destroy(P);
-
- P = proj_create(PJ_DEFAULT_CTX, arg);
- pj_info = proj_pj_info(P);
- if ( !pj_info.has_inverse ) { proj_destroy(P); return 61; }
- pj_shrink (arg);
- if ( strcmp(pj_info.definition, arg) ) { proj_destroy(P); return 62; }
- if ( strcmp(pj_info.id, "utm") ) { proj_destroy(P); return 63; }
-
- proj_destroy(P);
-
- /* proj_grid_info() */
- grid_info = proj_grid_info("null");
- if ( strlen(grid_info.filename) == 0 ) return 64;
- if ( strcmp(grid_info.gridname, "null") ) return 65;
- grid_info = proj_grid_info("nonexistinggrid");
- if ( strlen(grid_info.filename) > 0 ) return 66;
-
- /* proj_init_info() */
- init_info = proj_init_info("unknowninit");
- if ( strlen(init_info.filename) != 0 ) return 67;
-
- init_info = proj_init_info("epsg");
- /* Need to allow for "Unknown" until all commonly distributed EPSG-files comes with a metadata section */
- if ( strcmp(init_info.origin, "EPSG") && strcmp(init_info.origin, "Unknown") ) return 69;
- if ( strcmp(init_info.name, "epsg") ) return 68;
-
-
- /* test proj_rtodms() and proj_dmstor() */
- if (strcmp("180dN", proj_rtodms(buf, M_PI, 'N', 'S')))
- return 70;
-
- if (proj_dmstor(&buf[0], NULL) != M_PI)
- return 71;
-
- if (strcmp("114d35'29.612\"S", proj_rtodms(buf, -2.0, 'N', 'S')))
- return 72;
-
- /* we can't expect perfect numerical accuracy so testing with a tolerance */
- if (fabs(-2.0 - proj_dmstor(&buf[0], NULL)) > 1e-7)
- return 73;
-
-
- /* 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 = PJ_TORAD(12);
- a.lp.phi = PJ_TORAD(55);
-
- factors = proj_factors(P, a);
- if (proj_errno(P))
- return 85; /* factors not created correctly */
-
- /* check a few key characteristics of the Mercator projection */
- if (factors.angular_distortion != 0.0) return 86; /* angular distortion should be 0 */
- if (factors.meridian_parallel_angle != M_PI_2) return 87; /* Meridian/parallel angle should be 90 deg */
- if (factors.meridian_convergence != 0.0) return 88; /* 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++;
- if (n == 0) return 90;
-
- n = 0;
- for (ellps_list = proj_list_ellps(); ellps_list->id; ++ellps_list) n++;
- if (n == 0) return 91;
-
- n = 0;
- for (unit_list = proj_list_units(); unit_list->id; ++unit_list) n++;
- if (n == 0) return 92;
-
- n = 0;
- for (pm_list = proj_list_prime_meridians(); pm_list->id; ++pm_list) n++;
- if (n == 0) return 93;
-
-
- /* check io-predicates */
-
- /* angular in on fwd, linear out */
- P = proj_create (PJ_DEFAULT_CTX, "+proj=cart +ellps=GRS80");
- if (0==P) return 0;
- if (!proj_angular_input (P, PJ_FWD)) return 100;
- if ( proj_angular_input (P, PJ_INV)) return 101;
- if ( proj_angular_output (P, PJ_FWD)) return 102;
- if (!proj_angular_output (P, PJ_INV)) return 103;
- P->inverted = 1;
- if ( proj_angular_input (P, PJ_FWD)) return 104;
- if (!proj_angular_input (P, PJ_INV)) return 105;
- if (!proj_angular_output (P, PJ_FWD)) return 106;
- if ( proj_angular_output (P, PJ_INV)) return 107;
- 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 "
- );
- if (0==P) return 0;
- if (!proj_angular_input (P, PJ_FWD)) return 108;
- if (!proj_angular_input (P, PJ_INV)) return 109;
- if (!proj_angular_output (P, PJ_FWD)) return 110;
- if (!proj_angular_output (P, PJ_INV)) return 111;
- P->inverted = 1;
- if (!proj_angular_input (P, PJ_FWD)) return 112;
- if (!proj_angular_input (P, PJ_INV)) return 113;
- if (!proj_angular_output (P, PJ_FWD)) return 114;
- if (!proj_angular_output (P, PJ_INV)) return 115;
- 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 +transpose +no_defs"
- );
- if (0==P) return 0;
- if (proj_angular_input (P, PJ_FWD)) return 116;
- if (proj_angular_input (P, PJ_INV)) return 117;
- if (proj_angular_output (P, PJ_FWD)) return 118;
- if (proj_angular_output (P, PJ_INV)) return 119;
- P->inverted = 1;
- if (proj_angular_input (P, PJ_FWD)) return 120;
- if (proj_angular_input (P, PJ_INV)) return 121;
- if (proj_angular_output (P, PJ_FWD)) return 122;
- if (proj_angular_output (P, PJ_INV)) return 123;
-
- /* We specified "no_defs" but didn't give any ellipsoid info */
- /* pj_init_ctx should default to WGS84 */
- if (P->a != 6378137.0) return 124;
- if (P->f != 1.0/298.257223563) return 125;
- proj_destroy(P);
-
- /* Test that pj_fwd* and pj_inv* returns NaNs when receiving NaN input */
- P = proj_create(PJ_DEFAULT_CTX, "+proj=merc");
- if (0==P) return 0;
- a = proj_coord(NAN, NAN, NAN, NAN);
- a = proj_trans(P, PJ_FWD, a);
- if ( !( isnan(a.v[0]) && isnan(a.v[1]) && isnan(a.v[2]) && isnan(a.v[3]) ) )
- return 126;
- a = proj_coord(NAN, NAN, NAN, NAN);
- a = proj_trans(P, PJ_INV, a);
- if ( !( isnan(a.v[0]) && isnan(a.v[1]) && isnan(a.v[2]) && isnan(a.v[3]) ) )
- return 127;
- proj_destroy(P);
-
- return 0;
-}
-
-
-
-
-static int 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);
- int ret = 0;
-
- if (P == 0)
- return 5;
-
- in = proj_coord(0.0, 0.0, 0.0, t_in);
-
- out = proj_trans(P, PJ_FWD, in);
- if (fabs(out.xyzt.t - t_exp) > tol) {
- proj_log_error(P, "out: %10.10g, expect: %10.10g", out.xyzt.t, t_exp);
- ret = 1;
- }
- out = proj_trans(P, PJ_INV, out);
- if (fabs(out.xyzt.t - t_in) > tol) {
- proj_log_error(P, "out: %10.10g, expect: %10.10g", out.xyzt.t, t_in);
- ret = 2;
- }
- pj_free(P);
-
- proj_log_level(NULL, 0);
- return ret;
-}
-
-static int unitconvert_selftest (void) {
- int ret = 0;
- 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;
-
- ret = test_time(args1, 1e-6, in1, in1); if (ret) return ret + 10;
- ret = test_time(args2, 1e-6, in2, in2); if (ret) return ret + 20;
- ret = test_time(args3, 1e-6, in3, in3); if (ret) return ret + 30;
- ret = test_time(args4, 1e-6, in4, exp4); if (ret) return ret + 40;
- ret = test_time(args5, 1e-6, in5, in5); if (ret) return ret + 50;
-
- return 0;
-}
diff --git a/test/gie/more_builtins.gie b/test/gie/more_builtins.gie
index 13b77b0a..272e503c 100644
--- a/test/gie/more_builtins.gie
+++ b/test/gie/more_builtins.gie
@@ -709,11 +709,4 @@ direction reverse
accept 0 0 0 0
expect failure
--------------------------------------------------------------------------------
-run the few gie-builtin tests, which are currently either awkward or impossible
-to express in the gie command set
--------------------------------------------------------------------------------
-builtins
--------------------------------------------------------------------------------
-
</gie>
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