/* Measure numerical deviation after n roundtrips fwd-inv (or inv-fwd) */ double proj_roundtrip (PJ *P, PJ_DIRECTION direction, int n, PJ_COORD *coord) { int i; PJ_COORD t, org; if (0==P) return HUGE_VAL; if (n < 1) { proj_errno_set (P, EINVAL); return HUGE_VAL; } /* in the first half-step, we generate the output value */ org = *coord; *coord = proj_trans (P, direction, org); t = *coord; /* now we take n-1 full steps in inverse direction: We are */ /* out of phase due to the half step already taken */ for (i = 0; i < n - 1; i++) t = proj_trans (P, direction, proj_trans (P, -direction, t) ); /* finally, we take the last half-step */ t = proj_trans (P, -direction, t); /* checking for angular *input* since we do a roundtrip, and end where we begin */ if (proj_angular_input (P, direction)) return proj_lpz_dist (P, org, t); return proj_xyz_dist (org, t); }
int proj_angular_output (PJ *P, enum PJ_DIRECTION dir) { /****************************************************************************** Returns 1 if the operator P provides angular output coordinates when operating in direction dir, 0 otherwise. dir: {PJ_FWD, PJ_INV} ******************************************************************************/ return proj_angular_input (P, -dir); }
/* file processing function */ static void process(FILE *fid) { char line[MAX_LINE+3], *s = nullptr, pline[40]; PJ_COORD data; for (;;) { int facs_bad = 0; ++emess_dat.File_line; if (bin_in) { /* binary input */ if (fread(&data, sizeof(PJ_UV), 1, fid) != 1) break; } else { /* ascii input */ if (!(s = fgets(line, MAX_LINE, fid))) break; if (!strchr(s, '\n')) { /* overlong line */ int c; (void)strcat(s, "\n"); /* gobble up to newline */ while ((c = fgetc(fid)) != EOF && c != '\n') ; } if (*s == tag) { if (!bin_out) (void)fputs(line, stdout); continue; } if (reversein) { data.uv.v = (*informat)(s, &s); data.uv.u = (*informat)(s, &s); } else { data.uv.u = (*informat)(s, &s); data.uv.v = (*informat)(s, &s); } if (data.uv.v == HUGE_VAL) data.uv.u = HUGE_VAL; if (!*s && (s > line)) --s; /* assumed we gobbled \n */ if (!bin_out && echoin) { char t; t = *s; *s = '\0'; (void)fputs(line, stdout); *s = t; putchar('\t'); } } if (data.uv.u != HUGE_VAL) { PJ_COORD coord; coord.lp = data.lp; if (prescale) { data.uv.u *= fscale; data.uv.v *= fscale; } if (dofactors && !inverse) { facs = proj_factors(Proj, coord); facs_bad = proj_errno(Proj); } data.xy = (*proj.fwd)(data.lp, Proj); if (dofactors && inverse) { facs = proj_factors(Proj, coord); facs_bad = proj_errno(Proj); } if (postscale && data.uv.u != HUGE_VAL) { data.uv.u *= fscale; data.uv.v *= fscale; } } if (bin_out) { /* binary output */ (void)fwrite(&data, sizeof(PJ_UV), 1, stdout); continue; } else if (data.uv.u == HUGE_VAL) /* error output */ (void)fputs(oterr, stdout); else if (inverse && !oform) { /*ascii DMS output */ if (reverseout) { (void)fputs(rtodms(pline, data.uv.v, 'N', 'S'), stdout); putchar('\t'); (void)fputs(rtodms(pline, data.uv.u, 'E', 'W'), stdout); } else { (void)fputs(rtodms(pline, data.uv.u, 'E', 'W'), stdout); putchar('\t'); (void)fputs(rtodms(pline, data.uv.v, 'N', 'S'), stdout); } } else { /* x-y or decimal degree ascii output, scale if warranted by output units */ if (inverse) { if (proj_angular_input(Proj, PJ_FWD)) { data.uv.v *= RAD_TO_DEG; data.uv.u *= RAD_TO_DEG; } } else { if (proj_angular_output(Proj, PJ_FWD)) { data.uv.v *= RAD_TO_DEG; data.uv.u *= RAD_TO_DEG; } } if (reverseout) { (void)printf(oform, data.uv.v); putchar('\t'); (void)printf(oform, data.uv.u); } else { (void)printf(oform, data.uv.u); putchar('\t'); (void)printf(oform, data.uv.v); } } /* print scale factor data */ if (dofactors) { if (!facs_bad) (void)printf("\t<%g %g %g %g %g %g>", facs.meridional_scale, facs.parallel_scale, facs.areal_scale, facs.angular_distortion * RAD_TO_DEG, facs.tissot_semimajor, facs.tissot_semiminor); else (void)fputs("\t<* * * * * *>", stdout); } (void)fputs(bin_in ? "\n" : s, stdout); } }
int main(int argc, char **argv) { char *arg, *pargv[MAX_PARGS]; char **eargv = argv; FILE *fid; int pargc = 0, eargc = 0, mon = 0; if ( (emess_dat.Prog_name = strrchr(*argv,DIR_CHAR)) != nullptr) ++emess_dat.Prog_name; else emess_dat.Prog_name = *argv; inverse = ! strncmp(emess_dat.Prog_name, "inv", 3); if (argc <= 1 ) { (void)fprintf(stderr, usage, pj_get_release(), emess_dat.Prog_name); exit (0); } /* process run line arguments */ while (--argc > 0) { /* collect run line arguments */ if(**++argv == '-') for(arg = *argv;;) { switch(*++arg) { case '\0': /* position of "stdin" */ if (arg[-1] == '-') eargv[eargc++] = const_cast<char*>("-"); break; case 'b': /* binary I/O */ bin_in = bin_out = 1; continue; case 'v': /* monitor dump of initialization */ mon = 1; continue; case 'i': /* input binary */ bin_in = 1; continue; case 'o': /* output binary */ bin_out = 1; continue; case 'I': /* alt. method to spec inverse */ inverse = 1; continue; case 'E': /* echo ascii input to ascii output */ echoin = 1; continue; case 'V': /* very verbose processing mode */ very_verby = 1; mon = 1; continue; case 'S': /* compute scale factors */ dofactors = 1; continue; case 't': /* set col. one char */ if (arg[1]) tag = *++arg; else emess(1,"missing -t col. 1 tag"); continue; case 'l': /* list projections, ellipses or units */ if (!arg[1] || arg[1] == 'p' || arg[1] == 'P') { /* list projections */ const struct PJ_LIST *lp; int do_long = arg[1] == 'P', c; const char *str; for (lp = proj_list_operations() ; lp->id ; ++lp) { if( strcmp(lp->id,"latlong") == 0 || strcmp(lp->id,"longlat") == 0 || strcmp(lp->id,"geocent") == 0 ) continue; (void)printf("%s : ", lp->id); if (do_long) /* possibly multiline description */ (void)puts(*lp->descr); else { /* first line, only */ str = *lp->descr; while ((c = *str++) && c != '\n') putchar(c); putchar('\n'); } } } else if (arg[1] == '=') { /* list projection 'descr' */ const struct PJ_LIST *lp; arg += 2; for (lp = proj_list_operations(); lp->id ; ++lp) if (!strcmp(lp->id, arg)) { (void)printf("%9s : %s\n", lp->id, *lp->descr); break; } } else if (arg[1] == 'e') { /* list ellipses */ const struct PJ_ELLPS *le; for (le = proj_list_ellps(); le->id ; ++le) (void)printf("%9s %-16s %-16s %s\n", le->id, le->major, le->ell, le->name); } else if (arg[1] == 'u') { /* list units */ const struct PJ_UNITS *lu; for (lu = proj_list_units(); lu->id ; ++lu) (void)printf("%12s %-20s %s\n", lu->id, lu->to_meter, lu->name); } else if (arg[1] == 'd') { /* list datums */ const struct PJ_DATUMS *ld; printf("__datum_id__ __ellipse___ __definition/comments______________________________\n" ); for (ld = pj_get_datums_ref(); ld->id ; ++ld) { printf("%12s %-12s %-30s\n", ld->id, ld->ellipse_id, ld->defn); if( ld->comments != nullptr && strlen(ld->comments) > 0 ) printf( "%25s %s\n", " ", ld->comments ); } } else emess(1,"invalid list option: l%c",arg[1]); exit(0); /* cppcheck-suppress duplicateBreak */ continue; /* artificial */ case 'e': /* error line alternative */ if (--argc <= 0) noargument: emess(1,"missing argument for -%c",*arg); oterr = *++argv; continue; case 'm': /* cartesian multiplier */ if (--argc <= 0) goto noargument; postscale = 1; if (!strncmp("1/",*++argv,2) || !strncmp("1:",*argv,2)) { if((fscale = atof((*argv)+2)) == 0.) goto badscale; fscale = 1. / fscale; } else if ((fscale = atof(*argv)) == 0.) { badscale: emess(1,"invalid scale argument"); } continue; case 'W': /* specify seconds precision */ case 'w': /* -W for constant field width */ { int c = arg[1]; if (c != 0 && isdigit(c)) { set_rtodms(c - '0', *arg == 'W'); ++arg; } else emess(1,"-W argument missing or non-digit"); continue; } case 'f': /* alternate output format degrees or xy */ if (--argc <= 0) goto noargument; oform = *++argv; continue; case 'd': if (--argc <= 0) goto noargument; sprintf(oform_buffer, "%%.%df", atoi(*++argv)); oform = oform_buffer; break; case 'r': /* reverse input */ reversein = 1; continue; case 's': /* reverse output */ reverseout = 1; continue; default: emess(1, "invalid option: -%c",*arg); break; } break; } else if (**argv == '+') { /* + argument */ if (pargc < MAX_PARGS) pargv[pargc++] = *argv + 1; else emess(1,"overflowed + argument table"); } else /* assumed to be input file name(s) */ eargv[eargc++] = *argv; } if (eargc == 0) /* if no specific files force sysin */ eargv[eargc++] = const_cast<char*>("-"); /* done with parameter and control input */ if (inverse && postscale) { prescale = 1; postscale = 0; fscale = 1./fscale; } if (!(Proj = pj_init(pargc, pargv))) emess(3,"projection initialization failure\ncause: %s", pj_strerrno(pj_errno)); if (!proj_angular_input(Proj, PJ_FWD)) { emess(3, "can't initialize operations that take non-angular input coordinates"); exit(0); } if (proj_angular_output(Proj, PJ_FWD)) { emess(3, "can't initialize operations that produce angular output coordinates"); exit(0); } if (inverse) { if (!Proj->inv) emess(3,"inverse projection not available"); proj.inv = pj_inv; } else proj.fwd = pj_fwd; /* set input formatting control */ if (mon) { pj_pr_list(Proj); if (very_verby) { (void)printf("#Final Earth figure: "); if (Proj->es != 0.0) { (void)printf("ellipsoid\n# Major axis (a): "); (void)printf(oform ? oform : "%.3f", Proj->a); (void)printf("\n# 1/flattening: %.6f\n", 1./(1. - sqrt(1. - Proj->es))); (void)printf("# squared eccentricity: %.12f\n", Proj->es); } else { (void)printf("sphere\n# Radius: "); (void)printf(oform ? oform : "%.3f", Proj->a); (void)putchar('\n'); } } } if (inverse) informat = strtod; else { informat = proj_dmstor; if (!oform) oform = "%.2f"; } if (bin_out) { SET_BINARY_MODE(stdout); } /* process input file list */ for ( ; eargc-- ; ++eargv) { if (**eargv == '-') { fid = stdin; emess_dat.File_name = const_cast<char*>("<stdin>"); if (bin_in) { SET_BINARY_MODE(stdin); } } else { if ((fid = fopen(*eargv, "rb")) == nullptr) { emess(-2, *eargv, "input file"); continue; } emess_dat.File_name = *eargv; } emess_dat.File_line = 0; if (very_verby) vprocess(fid); else process(fid); (void)fclose(fid); emess_dat.File_name = nullptr; } if( Proj ) pj_free(Proj); exit(0); /* normal completion */ }
static int expect (const char *args) { /***************************************************************************** Tell GIE what to expect, when transforming the ACCEPTed input ******************************************************************************/ PJ_COORD ci, co, ce; double d; int expect_failure = 0; int expect_failure_with_errno = 0; if (0==strncmp (args, "failure", 7)) { expect_failure = 1; /* Option: Fail with an expected errno (syntax: expect failure errno -33) */ if (0==strncmp (column (args, 2), "errno", 5)) expect_failure_with_errno = errno_from_err_const (column (args, 3)); } if (T.ignore==proj_errno(T.P)) return another_skip (); if (nullptr==T.P) { /* If we expect failure, and fail, then it's a success... */ if (expect_failure) { /* Failed to fail correctly? */ if (expect_failure_with_errno && proj_errno (T.P)!=expect_failure_with_errno) return expect_failure_with_errno_message (expect_failure_with_errno, proj_errno(T.P)); return another_succeeding_failure (); } /* Otherwise, it's a true failure */ banner (T.operation); errmsg (3, "%sInvalid operation definition in line no. %d:\n %s (errno=%s/%d)\n", delim, (int) T.operation_lineno, pj_strerrno(proj_errno(T.P)), err_const_from_errno (proj_errno(T.P)), proj_errno(T.P) ); return another_failing_failure (); } /* We may still successfully fail even if the proj_create succeeded */ if (expect_failure) { proj_errno_reset (T.P); /* Try to carry out the operation - and expect failure */ ci = proj_angular_input (T.P, T.dir)? torad_coord (T.P, T.dir, T.a): T.a; co = expect_trans_n_dim (ci); if (expect_failure_with_errno) { if (proj_errno (T.P)==expect_failure_with_errno) return another_succeeding_failure (); fprintf (T.fout, "errno=%d, expected=%d\n", proj_errno (T.P), expect_failure_with_errno); return another_failing_failure (); } /* Succeeded in failing? - that's a success */ if (co.xyz.x==HUGE_VAL) return another_succeeding_failure (); /* Failed to fail? - that's a failure */ banner (T.operation); errmsg (3, "%sFailed to fail. Operation definition in line no. %d\n", delim, (int) T.operation_lineno ); return another_failing_failure (); } if (T.verbosity > 3) { fprintf (T.fout, "%s\n", T.P->inverted? "INVERTED": "NOT INVERTED"); fprintf (T.fout, "%s\n", T.dir== 1? "forward": "reverse"); fprintf (T.fout, "%s\n", proj_angular_input (T.P, T.dir)? "angular in": "linear in"); fprintf (T.fout, "%s\n", proj_angular_output (T.P, T.dir)? "angular out": "linear out"); fprintf (T.fout, "left: %d right: %d\n", T.P->left, T.P->right); } tests++; T.e = parse_coord (args); if (HUGE_VAL==T.e.v[0]) return expect_message_cannot_parse (args); /* expected angular values, probably in degrees */ ce = proj_angular_output (T.P, T.dir)? torad_coord (T.P, T.dir, T.e): T.e; if (T.verbosity > 3) fprintf (T.fout, "EXPECTS %.12f %.12f %.12f %.12f\n", ce.v[0],ce.v[1],ce.v[2],ce.v[3]); /* input ("accepted") values, also probably in degrees */ ci = proj_angular_input (T.P, T.dir)? torad_coord (T.P, T.dir, T.a): T.a; if (T.verbosity > 3) fprintf (T.fout, "ACCEPTS %.12f %.12f %.12f %.12f\n", ci.v[0],ci.v[1],ci.v[2],ci.v[3]); /* do the transformation, but mask off dimensions not given in expect-ation */ co = expect_trans_n_dim (ci); if (T.dimensions_given < 4) co.v[3] = 0; if (T.dimensions_given < 3) co.v[2] = 0; /* angular output from proj_trans comes in radians */ T.b = proj_angular_output (T.P, T.dir)? todeg_coord (T.P, T.dir, co): co; if (T.verbosity > 3) fprintf (T.fout, "GOT %.12f %.12f %.12f %.12f\n", co.v[0],co.v[1],co.v[2],co.v[3]); #if 0 /* We need to handle unusual axis orders - that'll be an item for version 5.1 */ if (T.P->axisswap) { ce = proj_trans (T.P->axisswap, T.dir, ce); co = proj_trans (T.P->axisswap, T.dir, co); } #endif if (proj_angular_output (T.P, T.dir)) d = proj_lpz_dist (T.P, ce, co); else d = proj_xyz_dist (co, ce); if (d > T.tolerance) return expect_message (d, args); succs++; another_success (); return 0; }
static int roundtrip (const char *args) { /***************************************************************************** Check how far we go from the ACCEPTed point when doing successive back/forward transformation pairs. Without args, roundtrip defaults to 100 iterations: roundtrip With one arg, roundtrip will default to a tolerance of T.tolerance: roundtrip ntrips With two args: roundtrip ntrips tolerance Always returns 0. ******************************************************************************/ int ntrips; double d, r, ans; char *endp; PJ_COORD coo; if (nullptr==T.P) { if (T.ignore == proj_errno(T.P)) return another_skip(); return another_failure (); } ans = proj_strtod (args, &endp); if (endp==args) { /* Default to 100 iterations if not args. */ ntrips = 100; } else { if (ans < 1.0 || ans > 1000000.0) { errmsg (2, "Invalid number of roundtrips: %lf\n", ans); return another_failing_roundtrip (); } ntrips = (int)ans; } d = strtod_scaled (endp, 1); d = d==HUGE_VAL? T.tolerance: d; /* input ("accepted") values - probably in degrees */ coo = proj_angular_input (T.P, T.dir)? torad_coord (T.P, T.dir, T.a): T.a; r = proj_roundtrip (T.P, T.dir, ntrips, &coo); if (r <= d) return another_succeeding_roundtrip (); if (T.verbosity > -1) { if (0==T.op_ko && T.verbosity < 2) banner (T.operation); fprintf (T.fout, "%s", T.op_ko? " -----\n": delim); fprintf (T.fout, " FAILURE in %s(%d):\n", opt_strip_path (T.curr_file), (int) F->lineno); fprintf (T.fout, " roundtrip deviation: %.6f mm, expected: %.6f mm\n", 1000*r, 1000*d); } return another_failing_roundtrip (); }