diff options
Diffstat (limited to 'src/pj_generic_selftest.c')
| -rw-r--r-- | src/pj_generic_selftest.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/pj_generic_selftest.c b/src/pj_generic_selftest.c new file mode 100644 index 00000000..88b5c308 --- /dev/null +++ b/src/pj_generic_selftest.c @@ -0,0 +1,197 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Generic regression test for PROJ.4 projection algorithms. + * Author: Thomas Knudsen + * + ****************************************************************************** + * Copyright (c) 2016, Thomas Knudsen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *****************************************************************************/ + + +#include <stdio.h> +#define PJ_LIB__ +#include <projects.h> + + +static int deviates_xy (XY expected, XY got, double tolerance); +static int deviates_lp (LP expected, LP got, double tolerance); +static XY pj_fwd_deg (LP in, PJ *P); + + +/**********************************************************************/ +int pj_generic_selftest ( +/**********************************************************************/ + char *e_args, + char *s_args, + double tolerance_xy, + double tolerance_lp, + int n_fwd, + int n_inv, + LP *fwd_in, + XY *e_fwd_expect, + XY *s_fwd_expect, + XY *inv_in, + LP *e_inv_expect, + LP *s_inv_expect +) { +/*********************************************************************** + +Generic regression test for PROJ.4 projection algorithms, testing both +ellipsoidal ("e_") and spheroidal ("s_") versions of the projection +algorithms in both forward ("_fwd_") and inverse ("_inv_") mode. + +Compares the "known good" results in <e_fwd_expect> and <s_fwd_expect> +with the actual results obtained by transforming the forward input data +set in <fwd_in> with pj_fwd() using setup arguments <e_args> and +<s_args>, respectively. + +Then + +Compares the "known good" results in <e_inv_expect> and <s_inv_expect> +with the actual results obtained by transforming the inverse input data +set in <inv_in> with pj_inv() using setup arguments <e_args> and +<s_args>, respectively. + +Any of the pointers passed may be set to 0, indicating "don't test this +part". + +Returns 0 if all data agree to within the accuracy specified in +<tolerance_xy> and <tolerance_lp>. Non-zero otherwise. + +***********************************************************************/ + int i; + + PJ *P; + + if (e_args) { + P = pj_init_plus(e_args); + if (0==P) + return 2; + + /* Test forward ellipsoidal */ + if (e_fwd_expect) { + for (i = 0; i < n_fwd; i++) + if (deviates_xy (e_fwd_expect[i], pj_fwd_deg ( fwd_in[i], P ), tolerance_xy)) + break; + if ( i != n_fwd ) + return 100 + i; + } + + /* Test inverse ellipsoidal */ + if (e_inv_expect) { + for (i = 0; i < n_inv; i++) + if (deviates_lp (e_inv_expect[i], pj_inv ( inv_in[i], P ), tolerance_lp)) + break; + if ( i != n_inv ) + return 200 + i; + } + + pj_free (P); + } + + + if (s_args) { + P = pj_init_plus(s_args); + if (0==P) + return 3; + + /* Test forward spherical */ + if (s_fwd_expect) { + for (i = 0; i < n_fwd; i++) + if (deviates_xy (s_fwd_expect[i], pj_fwd_deg ( fwd_in[i], P ), tolerance_xy)) + break; + if ( i != n_fwd ) + return 300 + i; + } + + /* Test inverse spherical */ + if (s_inv_expect) { + for (i = 0; i < n_inv; i++) + if (deviates_lp (s_inv_expect[i], pj_inv ( inv_in[i], P ), tolerance_lp)) + break; + if ( i != n_inv ) + return 400 + i; + } + + pj_free (P); + } + + return 0; +} + + + +/**********************************************************************/ +static int deviates_xy (XY expected, XY got, double tolerance) { +/*********************************************************************** + + Determine whether two XYs deviate by more than <tolerance>. + + The test material ("expected" values) may contain coordinates that + are indeterminate. For those cases, we test the other coordinate + only by forcing expected and actual ("got") coordinates to 0. + +***********************************************************************/ + if (HUGE_VAL== expected.x) + return 0; + if (HUGE_VAL== expected.y) + return 0; + if (hypot ( expected.x - got.x, expected.y - got.y ) > tolerance) + return 1; + return 0; +} + + +/**********************************************************************/ +static int deviates_lp (LP expected, LP got, double tolerance) { +/*********************************************************************** + + Determine whether two LPs deviate by more than <tolerance>. + + This one is slightly tricky, since the <expected> LP is + supposed to be represented as degrees (since it was at some + time written down by a real human), whereas the <got> LP is + represented in radians (since it is supposed to be the result + output from pj_inv) + +***********************************************************************/ + if (HUGE_VAL== expected.lam) + return 0; + if (HUGE_VAL== expected.phi) + return 0; + if (hypot ( DEG_TO_RAD * expected.lam - got.lam, DEG_TO_RAD * expected.phi - got.phi ) > tolerance) + return 1; + return 0; +} + + +/**********************************************************************/ +static XY pj_fwd_deg (LP in, PJ *P) { +/*********************************************************************** + + Wrapper for pj_fwd, accepting input in degrees. + +***********************************************************************/ + LP in_rad; + in_rad.lam = DEG_TO_RAD * in.lam; + in_rad.phi = DEG_TO_RAD * in.phi; + return pj_fwd (in_rad, P); +} |
