struct CTABLE *nad_ctable_init( projCtx ctx, FILE * fid ) { struct CTABLE *ct; int id_end; /* read the table header */ ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); if( ct == NULL || fread( ct, sizeof(struct CTABLE), 1, fid ) != 1 ) { pj_ctx_set_errno( ctx, -38 ); return NULL; } /* do some minimal validation to ensure the structure isn't corrupt */ if( ct->lim.lam < 1 || ct->lim.lam > 100000 || ct->lim.phi < 1 || ct->lim.phi > 100000 ) { pj_ctx_set_errno( ctx, -38 ); return NULL; } /* trim white space and newlines off id */ for( id_end = strlen(ct->id)-1; id_end > 0; id_end-- ) { if( ct->id[id_end] == '\n' || ct->id[id_end] == ' ' ) ct->id[id_end] = '\0'; else break; } ct->cvs = NULL; return ct; }
int nad_ctable2_load( projCtx ctx, struct CTABLE *ct, FILE *fid ) { int a_size; fseek( fid, 160, SEEK_SET ); /* read all the actual shift values */ a_size = ct->lim.lam * ct->lim.phi; ct->cvs = (FLP *) pj_malloc(sizeof(FLP) * a_size); if( ct->cvs == NULL || fread(ct->cvs, sizeof(FLP), a_size, fid) != a_size ) { pj_dalloc( ct->cvs ); ct->cvs = NULL; if( getenv("PROJ_DEBUG") != NULL ) { fprintf( stderr, "ctable2 loading failed on fread() - binary incompatible?\n" ); } pj_ctx_set_errno( ctx, -38 ); return 0; } if( !IS_LSB ) { swap_words( ct->cvs, 4, a_size * 2 ); } return 1; }
XY /* forward projection entry */ pj_fwd(LP lp, PJ *P) { XY xy; double t; /* check for forward and latitude or longitude overange */ if ((t = fabs(lp.phi)-HALFPI) > EPS || fabs(lp.lam) > 10.) { xy.x = xy.y = HUGE_VAL; pj_ctx_set_errno( P->ctx, -14); } else { /* proceed with projection */ P->ctx->last_errno = 0; pj_errno = 0; errno = 0; if (fabs(t) <= EPS) lp.phi = lp.phi < 0. ? -HALFPI : HALFPI; else if (P->geoc) lp.phi = atan(P->rone_es * tan(lp.phi)); lp.lam -= P->lam0; /* compute del lp.lam */ if (!P->over) lp.lam = adjlon(lp.lam); /* adjust del longitude */ xy = (*P->fwd)(lp, P); /* project */ if ( P->ctx->last_errno ) xy.x = xy.y = HUGE_VAL; /* adjust for major axis and easting/northings */ else { xy.x = P->fr_meter * (P->a * xy.x + P->x0); xy.y = P->fr_meter * (P->a * xy.y + P->y0); } } return xy; }
static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ XY xy = {0.0,0.0}; double b, cosphi; /* * Fail if our longitude is more than 90 degrees from the * central meridian since the results are essentially garbage. * Is error -20 really an appropriate return value? * * http://trac.osgeo.org/proj/ticket/5 */ if( lp.lam < -HALFPI || lp.lam > HALFPI ) { xy.x = HUGE_VAL; xy.y = HUGE_VAL; pj_ctx_set_errno( P->ctx, -14 ); return xy; } cosphi = cos(lp.phi); b = cosphi * sin (lp.lam); if (fabs (fabs (b) - 1.) <= EPS10) F_ERROR; xy.x = P->opaque->ml0 * log ((1. + b) / (1. - b)); xy.y = cosphi * cos (lp.lam) / sqrt (1. - b * b); b = fabs ( xy.y ); if (b >= 1.) { if ((b - 1.) > EPS10) F_ERROR else xy.y = 0.; } else
double aacos(projCtx ctx, double v) { double av; if ((av = fabs(v)) >= 1.) { if (av > ONE_TOL) pj_ctx_set_errno(ctx, -19); return (v < 0. ? PI : 0.); } return acos(v); }
double aasin(projCtx ctx, double v) { double av; if ((av = fabs(v)) >= 1.) { if (av > ONE_TOL) pj_ctx_set_errno(ctx, -19); return (v < 0. ? -HALFPI : HALFPI); } return asin(v); }
static PJ_LP 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; int i; /* Adjusting x and y for authalic radius */ xy.x /= Q->rqda; xy.y /= Q->rqda; /* Make sure y is inside valid range */ if (xy.y > MAX_Y) xy.y = MAX_Y; else if (xy.y < -MAX_Y) xy.y = -MAX_Y; yc = xy.y; /* Newton-Raphson */ for (i = MAX_ITER; i ; --i) { double f, fder, tol; y2 = yc * yc; y6 = y2 * y2 * y2; f = yc * (A1 + A2 * y2 + y6 * (A3 + A4 * y2)) - xy.y; fder = A1 + 3 * A2 * y2 + y6 * (7 * A3 + 9 * A4 * y2); tol = f / fder; yc -= tol; if (fabs(tol) < EPS) break; } if( i == 0 ) { pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); return lp; } /* Longitude */ y2 = yc * yc; y6 = y2 * y2 * y2; lp.lam = M * xy.x * (A1 + 3 * A2 * y2 + y6 * (7 * A3 + 9 * A4 * y2)) / cos(yc); /* Latitude (for spheroidal case, this is latitude */ lp.phi = asin(sin(yc) / M); /* Ellipsoidal case, converting auth. latitude */ if (P->es != 0.0) lp.phi = pj_authlat(lp.phi, Q->apa); return lp; }
static LP s_healpix_inverse(XY xy, PJ *P) { /* sphere */ LP lp = {0.0,0.0}; /* Check whether (x, y) lies in the HEALPix image */ if (in_image(xy.x, xy.y, 0, 0, 0) == 0) { lp.lam = HUGE_VAL; lp.phi = HUGE_VAL; pj_ctx_set_errno(P->ctx, -15); return lp; } return healpix_sphere_inverse(xy); }
static LP e_healpix_inverse(XY xy, PJ *P) { /* ellipsoid */ LP lp = {0.0,0.0}; /* Check whether (x, y) lies in the HEALPix image. */ if (in_image(xy.x, xy.y, 0, 0, 0) == 0) { lp.lam = HUGE_VAL; lp.phi = HUGE_VAL; pj_ctx_set_errno(P->ctx, -15); return lp; } lp = healpix_sphere_inverse(xy); lp.phi = auth_lat(P, lp.phi, 1); return lp; }
static LP s_rhealpix_inverse(XY xy, PJ *P) { /* sphere */ struct pj_opaque *Q = P->opaque; LP lp = {0.0,0.0}; /* Check whether (x, y) lies in the rHEALPix image. */ if (in_image(xy.x, xy.y, 1, Q->north_square, Q->south_square) == 0) { lp.lam = HUGE_VAL; lp.phi = HUGE_VAL; pj_ctx_set_errno(P->ctx, -15); return lp; } xy = combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 1); return healpix_sphere_inverse(xy); }
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}; double u, deltav, s, d, eps, rho, fi1, xy0; int i; xy0 = xy.x; xy.x = xy.y; xy.y = xy0; xy.x *= Q->czech; xy.y *= Q->czech; rho = sqrt(xy.x * xy.x + xy.y * xy.y); eps = atan2(xy.y, xy.x); d = eps / sin(S0); 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)); lp.lam = P->lam0 - deltav / Q->alpha; /* ITERATION FOR lp.phi */ fi1 = u; for (i = MAX_ITER; i ; --i) { lp.phi = 2. * ( atan( pow( Q->k, -1. / Q->alpha) * pow( tan(u / 2. + M_PI_4) , 1. / Q->alpha) * pow( (1. + P->e * sin(fi1)) / (1. - P->e * sin(fi1)) , P->e / 2.) ) - M_PI_4); if (fabs(fi1 - lp.phi) < EPS) break; fi1 = lp.phi; } if( i == 0 ) pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); lp.lam -= P->lam0; return lp; }
static PJ_LP s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; long i; double t, t1; struct COEFS T; int iters; lp.lam = xy.x / FXC; lp.phi = fabs(xy.y / FYC); if (lp.phi >= 1.) { /* simple pathologic cases */ if (lp.phi > ONEEPS) { proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); return lp; } else { lp.phi = xy.y < 0. ? -M_HALFPI : M_HALFPI; lp.lam /= X[NODES].c0; } } else { /* general problem */ /* in Y space, reduce to table interval */ i = isnan(lp.phi) ? -1 : lround(floor(lp.phi * NODES)); if( i < 0 || i >= NODES ) { proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); return lp; } for (;;) { if (Y[i].c0 > lp.phi) --i; else if (Y[i+1].c0 <= lp.phi) ++i; else break; } 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); if (fabs(t1) < EPS) break; } if( iters == 0 ) pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); lp.phi = (5 * i + t) * DEG_TO_RAD; if (xy.y < 0.) lp.phi = -lp.phi; lp.lam /= V(X[i], t); } return lp; }
static paralist * get_init(projCtx ctx, paralist **start, paralist *next, char *name) { char fname[MAX_PATH_FILENAME+ID_TAG_MAX+3], *opt; FILE *fid; paralist *init_items = NULL; const paralist *orig_next = next; (void)strncpy(fname, name, MAX_PATH_FILENAME + ID_TAG_MAX + 1); /* ** Search for file/key pair in cache */ init_items = pj_search_initcache( name ); if( init_items != NULL ) { next->next = init_items; while( next->next != NULL ) next = next->next; return next; } /* ** Otherwise we try to open the file and search for it. */ if ((opt = strrchr(fname, ':')) != NULL) *opt++ = '\0'; else { pj_ctx_set_errno(ctx,-3); return NULL; } if ( (fid = pj_open_lib(ctx,fname, "rt")) != NULL) next = get_opt(ctx, start, fid, opt, next); else return NULL; (void)fclose(fid); if (errno == 25) errno = 0; /* unknown problem with some sys errno<-25 */ /* ** If we seem to have gotten a result, insert it into the ** init file cache. */ if( next != NULL && next != orig_next ) pj_insert_initcache( name, orig_next->next ); return next; }
double pj_phi2(projCtx ctx, double ts, double e) { double eccnth, Phi, con, dphi; int i; eccnth = .5 * e; Phi = HALFPI - 2. * atan (ts); i = N_ITER; do { con = e * sin (Phi); dphi = HALFPI - 2. * atan (ts * pow((1. - con) / (1. + con), eccnth)) - Phi; Phi += dphi; } while ( fabs(dphi) > TOL && --i); if (i <= 0) pj_ctx_set_errno( ctx, -18 ); return Phi; }
double proj_inv_mdist(projCtx ctx, double dist, const void *b) { double s, t, phi, k; int i; k = 1. / (1. - B->es); i = MAX_ITER; phi = dist; while (i--) { s = sin(phi); t = 1. - B->es * s * s; phi -= t = (proj_mdist(phi, s, cos(phi), b) - dist) * (t * sqrt(t)) * k; if (fabs(t) < TOL) /* that is no change */ return phi; } /* convergence failed */ pj_ctx_set_errno(ctx, -17); return phi; }
static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ XY xy = {0.0, 0.0}; struct pj_opaque *Q = P->opaque; double al, als, n, cosphi, sinphi, t; /* * Fail if our longitude is more than 90 degrees from the * central meridian since the results are essentially garbage. * Is error -20 really an appropriate return value? * * http://trac.osgeo.org/proj/ticket/5 */ if( lp.lam < -HALFPI || lp.lam > HALFPI ) { xy.x = HUGE_VAL; xy.y = HUGE_VAL; pj_ctx_set_errno( P->ctx, -14 ); return xy; } sinphi = sin (lp.phi); cosphi = cos (lp.phi); t = fabs (cosphi) > 1e-10 ? sinphi/cosphi : 0.; t *= t; al = cosphi * lp.lam; als = al * al; al /= sqrt (1. - P->es * sinphi * sinphi); n = Q->esp * cosphi * cosphi; xy.x = P->k0 * al * (FC1 + FC3 * als * (1. - t + n + FC5 * als * (5. + t * (t - 18.) + n * (14. - 58. * t) + FC7 * als * (61. + t * ( t * (179. - t) - 479. ) ) ))); xy.y = P->k0 * (pj_mlfn(lp.phi, sinphi, cosphi, Q->en) - Q->ml0 + sinphi * al * lp.lam * FC2 * ( 1. + FC4 * als * (5. - t + n * (9. + 4. * n) + FC6 * als * (61. + t * (t - 58.) + n * (270. - 330 * t) + FC8 * als * (1385. + t * ( t * (543. - t) - 3111.) ) )))); return (xy); }
LP /* inverse projection entry */ pj_inv(XY xy, PJ *P) { LP lp; /* can't do as much preliminary checking as with forward */ if (xy.x == HUGE_VAL || xy.y == HUGE_VAL) { lp.lam = lp.phi = HUGE_VAL; pj_ctx_set_errno( P->ctx, -15); return lp; } errno = pj_errno = 0; P->ctx->last_errno = 0; xy.x = (xy.x * P->to_meter - P->x0) * P->ra; /* descale and de-offset */ xy.y = (xy.y * P->to_meter - P->y0) * P->ra; //Check for NULL pointer if (P->inv != NULL) { lp = (*P->inv)(xy, P); /* inverse project */ if (P->ctx->last_errno ) lp.lam = lp.phi = HUGE_VAL; else { lp.lam += P->lam0; /* reduce from del lp.lam */ if (!P->over) lp.lam = adjlon(lp.lam); /* adjust longitude to CM */ if (P->geoc && fabs(fabs(lp.phi)-HALFPI) > EPS) lp.phi = atan(P->one_es * tan(lp.phi)); } } else { lp.lam = lp.phi = HUGE_VAL; } return lp; }
int proj_errno_reset (const PJ *P) { /****************************************************************************** Clears errno in the context and thread local levels through the low level pj_ctx interface. Returns the previous value of the errno, for convenient reset/restore operations: int foo (PJ *P) { // errno may be set on entry, but we need to reset it to be able to // check for errors from "do_something_with_P(P)" int last_errno = proj_errno_reset (P); // local failure if (0==P) return proj_errno_set (P, 42); // call to function that may fail do_something_with_P (P); // failure in do_something_with_P? - keep latest error status if (proj_errno(P)) return proj_errno (P); // success - restore previous error status, return 0 return proj_errno_restore (P, last_errno); } ******************************************************************************/ int last_errno; last_errno = proj_errno (P); pj_ctx_set_errno (pj_get_ctx ((PJ *) P), 0); errno = 0; pj_errno = 0; return last_errno; }
int nad_ctable_load( projCtx ctx, struct CTABLE *ct, FILE *fid ) { int a_size; fseek( fid, sizeof(struct CTABLE), SEEK_SET ); /* read all the actual shift values */ a_size = ct->lim.lam * ct->lim.phi; ct->cvs = (FLP *) pj_malloc(sizeof(FLP) * a_size); if( ct->cvs == NULL || fread(ct->cvs, sizeof(FLP), a_size, fid) != a_size ) { pj_dalloc( ct->cvs ); ct->cvs = NULL; pj_log( ctx, PJ_LOG_ERROR, "ctable loading failed on fread() - binary incompatible?\n" ); pj_ctx_set_errno( ctx, -38 ); return 0; } return 1; }
static int pj_gridinfo_init_ntv1( projCtx ctx, PAFile fid, PJ_GRIDINFO *gi ) { unsigned char header[176]; struct CTABLE *ct; LP ur; assert( sizeof(int) == 4 ); assert( sizeof(double) == 8 ); if( sizeof(int) != 4 || sizeof(double) != 8 ) { pj_log( ctx, PJ_LOG_ERROR, "basic types of inappropraiate size in nad_load_ntv1()" ); pj_ctx_set_errno( ctx, -38 ); return 0; } /* -------------------------------------------------------------------- */ /* Read the header. */ /* -------------------------------------------------------------------- */ if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) { pj_ctx_set_errno( ctx, -38 ); return 0; } /* -------------------------------------------------------------------- */ /* Regularize fields of interest. */ /* -------------------------------------------------------------------- */ if( IS_LSB ) { swap_words( header+8, 4, 1 ); swap_words( header+24, 8, 1 ); swap_words( header+40, 8, 1 ); swap_words( header+56, 8, 1 ); swap_words( header+72, 8, 1 ); swap_words( header+88, 8, 1 ); swap_words( header+104, 8, 1 ); } if( *((int *) (header+8)) != 12 ) { pj_log( ctx, PJ_LOG_ERROR, "NTv1 grid shift file has wrong record count, corrupt?" ); pj_ctx_set_errno( ctx, -38 ); return 0; } /* -------------------------------------------------------------------- */ /* Fill in CTABLE structure. */ /* -------------------------------------------------------------------- */ ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); strcpy( ct->id, "NTv1 Grid Shift File" ); ct->ll.lam = - *((double *) (header+72)); ct->ll.phi = *((double *) (header+24)); ur.lam = - *((double *) (header+56)); ur.phi = *((double *) (header+40)); ct->del.lam = *((double *) (header+104)); ct->del.phi = *((double *) (header+88)); ct->lim.lam = (int) (fabs(ur.lam-ct->ll.lam)/ct->del.lam + 0.5) + 1; ct->lim.phi = (int) (fabs(ur.phi-ct->ll.phi)/ct->del.phi + 0.5) + 1; pj_log( ctx, PJ_LOG_DEBUG_MINOR, "NTv1 %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", ct->lim.lam, ct->lim.phi, ct->ll.lam, ct->ll.phi, ur.lam, ur.phi ); ct->ll.lam *= DEG_TO_RAD; ct->ll.phi *= DEG_TO_RAD; ct->del.lam *= DEG_TO_RAD; ct->del.phi *= DEG_TO_RAD; ct->cvs = NULL; gi->ct = ct; gi->grid_offset = pj_ctx_ftell( ctx, fid ); gi->format = "ntv1"; return 1; }
double dmstor_ctx(projCtx ctx, const char *is, char **rs) { int sign, n, nl; char *s, work[MAX_WORK]; const char* p; double v, tv; if (rs) *rs = (char *)is; /* copy sting into work space */ while (isspace(sign = *is)) ++is; n = MAX_WORK; s = work; p = (char *)is; while (isgraph(*p) && --n) *s++ = *p++; *s = '\0'; /* it is possible that a really odd input (like lots of leading zeros) could be truncated in copying into work. But ... */ sign = *(s = work); if (sign == '+' || sign == '-') s++; else sign = '+'; v = 0.; for (nl = 0 ; nl < 3 ; nl = n + 1 ) { if (!(isdigit(*s) || *s == '.')) break; if ((tv = proj_strtod(s, &s)) == HUGE_VAL) return tv; switch (*s) { case 'D': case 'd': n = 0; break; case '\'': n = 1; break; case '"': n = 2; break; case 'r': case 'R': if (nl) { pj_ctx_set_errno( ctx, PJD_ERR_WRONG_FORMAT_DMS_VALUE ); return HUGE_VAL; } ++s; v = tv; goto skip; default: v += tv * vm[nl]; skip: n = 4; continue; } if (n < nl) { pj_ctx_set_errno( ctx, PJD_ERR_WRONG_FORMAT_DMS_VALUE ); return HUGE_VAL; } v += tv * vm[n]; ++s; } /* postfix sign */ if (*s && (p = strchr(sym, *s))) { sign = (p - sym) >= 4 ? '-' : '+'; ++s; } if (sign == '-') v = -v; if (rs) /* return point of next char after valid string */ *rs = (char *)is + (s - work); return v; }
PJ_GRIDINFO *pj_gridinfo_init( projCtx ctx, const char *gridname ) { char fname[MAX_PATH_FILENAME+1]; PJ_GRIDINFO *gilist; PAFile fp; char header[160]; size_t header_size = 0; errno = pj_errno = 0; ctx->last_errno = 0; /* -------------------------------------------------------------------- */ /* Initialize a GRIDINFO with stub info we would use if it */ /* cannot be loaded. */ /* -------------------------------------------------------------------- */ gilist = (PJ_GRIDINFO *) pj_calloc(1, sizeof(PJ_GRIDINFO)); if (!gilist) { pj_ctx_set_errno(ctx, ENOMEM); return NULL; } gilist->gridname = pj_strdup( gridname ); if (!gilist->gridname) { pj_dalloc(gilist); pj_ctx_set_errno(ctx, ENOMEM); return NULL; } gilist->filename = NULL; gilist->format = "missing"; gilist->grid_offset = 0; gilist->ct = NULL; gilist->next = NULL; /* -------------------------------------------------------------------- */ /* Open the file using the usual search rules. */ /* -------------------------------------------------------------------- */ strcpy(fname, gridname); if (!(fp = pj_open_lib(ctx, fname, "rb"))) { ctx->last_errno = 0; /* don't treat as a persistent error */ return gilist; } gilist->filename = pj_strdup(fname); if (!gilist->filename) { pj_dalloc(gilist->gridname); pj_dalloc(gilist); pj_ctx_set_errno(ctx, ENOMEM); return NULL; } /* -------------------------------------------------------------------- */ /* Load a header, to determine the file type. */ /* -------------------------------------------------------------------- */ if( (header_size = pj_ctx_fread( ctx, header, 1, sizeof(header), fp ) ) != sizeof(header) ) { /* some files may be smaller that sizeof(header), eg 160, so */ ctx->last_errno = 0; /* don't treat as a persistent error */ pj_log( ctx, PJ_LOG_DEBUG_MAJOR, "pj_gridinfo_init: short header read of %d bytes", (int)header_size ); } pj_ctx_fseek( ctx, fp, SEEK_SET, 0 ); /* -------------------------------------------------------------------- */ /* Determine file type. */ /* -------------------------------------------------------------------- */ if( header_size >= 144 + 16 && strncmp(header + 0, "HEADER", 6) == 0 && strncmp(header + 96, "W GRID", 6) == 0 && strncmp(header + 144, "TO NAD83 ", 16) == 0 ) { pj_gridinfo_init_ntv1( ctx, fp, gilist ); } else if( header_size >= 48 + 7 && strncmp(header + 0, "NUM_OREC", 8) == 0 && strncmp(header + 48, "GS_TYPE", 7) == 0 ) { pj_gridinfo_init_ntv2( ctx, fp, gilist ); } else if( strlen(gridname) > 4 && (strcmp(gridname+strlen(gridname)-3,"gtx") == 0 || strcmp(gridname+strlen(gridname)-3,"GTX") == 0) ) { pj_gridinfo_init_gtx( ctx, fp, gilist ); } else if( header_size >= 9 && strncmp(header + 0,"CTABLE V2",9) == 0 ) { struct CTABLE *ct = nad_ctable2_init( ctx, fp ); gilist->format = "ctable2"; gilist->ct = ct; if (ct == NULL) { pj_log( ctx, PJ_LOG_DEBUG_MAJOR, "CTABLE V2 ct is NULL."); } else { pj_log( ctx, PJ_LOG_DEBUG_MAJOR, "Ctable2 %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", ct->id, ct->lim.lam, ct->lim.phi, ct->ll.lam * RAD_TO_DEG, ct->ll.phi * RAD_TO_DEG, (ct->ll.lam + (ct->lim.lam-1)*ct->del.lam) * RAD_TO_DEG, (ct->ll.phi + (ct->lim.phi-1)*ct->del.phi) * RAD_TO_DEG ); } } else { struct CTABLE *ct = nad_ctable_init( ctx, fp ); if (ct == NULL) { pj_log( ctx, PJ_LOG_DEBUG_MAJOR, "CTABLE ct is NULL."); } else { gilist->format = "ctable"; gilist->ct = ct; pj_log( ctx, PJ_LOG_DEBUG_MAJOR, "Ctable %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", ct->id, ct->lim.lam, ct->lim.phi, ct->ll.lam * RAD_TO_DEG, ct->ll.phi * RAD_TO_DEG, (ct->ll.lam + (ct->lim.lam-1)*ct->del.lam) * RAD_TO_DEG, (ct->ll.phi + (ct->lim.phi-1)*ct->del.phi) * RAD_TO_DEG ); } } pj_ctx_fclose(ctx, fp); return gilist; }
static int pj_gridinfo_init_gtx( projCtx ctx, PAFile fid, PJ_GRIDINFO *gi ) { unsigned char header[40]; struct CTABLE *ct; double xorigin,yorigin,xstep,ystep; int rows, columns; /* cppcheck-suppress sizeofCalculation */ STATIC_ASSERT( sizeof(pj_int32) == 4 ); /* cppcheck-suppress sizeofCalculation */ STATIC_ASSERT( sizeof(double) == 8 ); /* -------------------------------------------------------------------- */ /* Read the header. */ /* -------------------------------------------------------------------- */ if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) { pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); return 0; } /* -------------------------------------------------------------------- */ /* Regularize fields of interest and extract. */ /* -------------------------------------------------------------------- */ if( IS_LSB ) { swap_words( header+0, 8, 4 ); swap_words( header+32, 4, 2 ); } memcpy( &yorigin, header+0, 8 ); memcpy( &xorigin, header+8, 8 ); memcpy( &ystep, header+16, 8 ); memcpy( &xstep, header+24, 8 ); memcpy( &rows, header+32, 4 ); memcpy( &columns, header+36, 4 ); if( xorigin < -360 || xorigin > 360 || yorigin < -90 || yorigin > 90 ) { pj_log( ctx, PJ_LOG_ERROR, "gtx file header has invalid extents, corrupt?"); pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); return 0; } /* -------------------------------------------------------------------- */ /* Fill in CTABLE structure. */ /* -------------------------------------------------------------------- */ ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); if (!ct) { pj_ctx_set_errno(ctx, ENOMEM); return 0; } strcpy( ct->id, "GTX Vertical Grid Shift File" ); ct->ll.lam = xorigin; ct->ll.phi = yorigin; ct->del.lam = xstep; ct->del.phi = ystep; ct->lim.lam = columns; ct->lim.phi = rows; /* some GTX files come in 0-360 and we shift them back into the expected -180 to 180 range if possible. This does not solve problems with grids spanning the dateline. */ if( ct->ll.lam >= 180.0 ) ct->ll.lam -= 360.0; if( ct->ll.lam >= 0.0 && ct->ll.lam + ct->del.lam * ct->lim.lam > 180.0 ) { pj_log( ctx, PJ_LOG_DEBUG_MAJOR, "This GTX spans the dateline! This will cause problems." ); } pj_log( ctx, PJ_LOG_DEBUG_MINOR, "GTX %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", ct->lim.lam, ct->lim.phi, ct->ll.lam, ct->ll.phi, ct->ll.lam + (columns-1)*xstep, ct->ll.phi + (rows-1)*ystep); ct->ll.lam *= DEG_TO_RAD; ct->ll.phi *= DEG_TO_RAD; ct->del.lam *= DEG_TO_RAD; ct->del.phi *= DEG_TO_RAD; ct->cvs = NULL; gi->ct = ct; gi->grid_offset = 40; gi->format = "gtx"; return 1; }
static int pj_gridinfo_init_ntv1( projCtx ctx, PAFile fid, PJ_GRIDINFO *gi ) { unsigned char header[176]; struct CTABLE *ct; LP ur; /* cppcheck-suppress sizeofCalculation */ STATIC_ASSERT( sizeof(pj_int32) == 4 ); /* cppcheck-suppress sizeofCalculation */ STATIC_ASSERT( sizeof(double) == 8 ); /* -------------------------------------------------------------------- */ /* Read the header. */ /* -------------------------------------------------------------------- */ if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) { pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); return 0; } /* -------------------------------------------------------------------- */ /* Regularize fields of interest. */ /* -------------------------------------------------------------------- */ if( IS_LSB ) { swap_words( header+8, 4, 1 ); swap_words( header+24, 8, 1 ); swap_words( header+40, 8, 1 ); swap_words( header+56, 8, 1 ); swap_words( header+72, 8, 1 ); swap_words( header+88, 8, 1 ); swap_words( header+104, 8, 1 ); } if( *((int *) (header+8)) != 12 ) { pj_log( ctx, PJ_LOG_ERROR, "NTv1 grid shift file has wrong record count, corrupt?" ); pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); return 0; } /* -------------------------------------------------------------------- */ /* Fill in CTABLE structure. */ /* -------------------------------------------------------------------- */ ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); if (!ct) { pj_ctx_set_errno(ctx, ENOMEM); return 0; } strcpy( ct->id, "NTv1 Grid Shift File" ); ct->ll.lam = - to_double(header+72); ct->ll.phi = to_double(header+24); ur.lam = - to_double(header+56); ur.phi = to_double(header+40); ct->del.lam = to_double(header+104); ct->del.phi = to_double(header+88); ct->lim.lam = (pj_int32) (fabs(ur.lam-ct->ll.lam)/ct->del.lam + 0.5) + 1; ct->lim.phi = (pj_int32) (fabs(ur.phi-ct->ll.phi)/ct->del.phi + 0.5) + 1; pj_log( ctx, PJ_LOG_DEBUG_MINOR, "NTv1 %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", ct->lim.lam, ct->lim.phi, ct->ll.lam, ct->ll.phi, ur.lam, ur.phi ); ct->ll.lam *= DEG_TO_RAD; ct->ll.phi *= DEG_TO_RAD; ct->del.lam *= DEG_TO_RAD; ct->del.phi *= DEG_TO_RAD; ct->cvs = NULL; gi->ct = ct; gi->grid_offset = pj_ctx_ftell( ctx, fid ); gi->format = "ntv1"; return 1; }
static int pj_gridinfo_init_ntv2( projCtx ctx, PAFile fid, PJ_GRIDINFO *gilist ) { unsigned char header[11*16]; int num_subfiles, subfile; int must_swap; /* cppcheck-suppress sizeofCalculation */ STATIC_ASSERT( sizeof(pj_int32) == 4 ); /* cppcheck-suppress sizeofCalculation */ STATIC_ASSERT( sizeof(double) == 8 ); /* -------------------------------------------------------------------- */ /* Read the overview header. */ /* -------------------------------------------------------------------- */ if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) { pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); return 0; } if( header[8] == 11 ) must_swap = !IS_LSB; else must_swap = IS_LSB; /* -------------------------------------------------------------------- */ /* Byte swap interesting fields if needed. */ /* -------------------------------------------------------------------- */ if( must_swap ) { swap_words( header+8, 4, 1 ); swap_words( header+8+16, 4, 1 ); swap_words( header+8+32, 4, 1 ); swap_words( header+8+7*16, 8, 1 ); swap_words( header+8+8*16, 8, 1 ); swap_words( header+8+9*16, 8, 1 ); swap_words( header+8+10*16, 8, 1 ); } /* -------------------------------------------------------------------- */ /* Get the subfile count out ... all we really use for now. */ /* -------------------------------------------------------------------- */ memcpy( &num_subfiles, header+8+32, 4 ); /* ==================================================================== */ /* Step through the subfiles, creating a PJ_GRIDINFO for each. */ /* ==================================================================== */ for( subfile = 0; subfile < num_subfiles; subfile++ ) { struct CTABLE *ct; LP ur; int gs_count; PJ_GRIDINFO *gi; /* -------------------------------------------------------------------- */ /* Read header. */ /* -------------------------------------------------------------------- */ if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) { pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); return 0; } if( strncmp((const char *) header,"SUB_NAME",8) != 0 ) { pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); return 0; } /* -------------------------------------------------------------------- */ /* Byte swap interesting fields if needed. */ /* -------------------------------------------------------------------- */ if( must_swap ) { swap_words( header+8+16*4, 8, 1 ); swap_words( header+8+16*5, 8, 1 ); swap_words( header+8+16*6, 8, 1 ); swap_words( header+8+16*7, 8, 1 ); swap_words( header+8+16*8, 8, 1 ); swap_words( header+8+16*9, 8, 1 ); swap_words( header+8+16*10, 4, 1 ); } /* -------------------------------------------------------------------- */ /* Initialize a corresponding "ct" structure. */ /* -------------------------------------------------------------------- */ ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); if (!ct) { pj_ctx_set_errno(ctx, ENOMEM); return 0; } strncpy( ct->id, (const char *) header + 8, 8 ); ct->id[8] = '\0'; ct->ll.lam = - to_double(header+7*16+8); /* W_LONG */ ct->ll.phi = to_double(header+4*16+8); /* S_LAT */ ur.lam = - to_double(header+6*16+8); /* E_LONG */ ur.phi = to_double(header+5*16+8); /* N_LAT */ ct->del.lam = to_double(header+9*16+8); ct->del.phi = to_double(header+8*16+8); ct->lim.lam = (pj_int32) (fabs(ur.lam-ct->ll.lam)/ct->del.lam + 0.5) + 1; ct->lim.phi = (pj_int32) (fabs(ur.phi-ct->ll.phi)/ct->del.phi + 0.5) + 1; pj_log( ctx, PJ_LOG_DEBUG_MINOR, "NTv2 %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", ct->id, ct->lim.lam, ct->lim.phi, ct->ll.lam/3600.0, ct->ll.phi/3600.0, ur.lam/3600.0, ur.phi/3600.0 ); ct->ll.lam *= DEG_TO_RAD/3600.0; ct->ll.phi *= DEG_TO_RAD/3600.0; ct->del.lam *= DEG_TO_RAD/3600.0; ct->del.phi *= DEG_TO_RAD/3600.0; memcpy( &gs_count, header + 8 + 16*10, 4 ); if( gs_count != ct->lim.lam * ct->lim.phi ) { pj_log( ctx, PJ_LOG_ERROR, "GS_COUNT(%d) does not match expected cells (%dx%d=%d)", gs_count, ct->lim.lam, ct->lim.phi, ct->lim.lam * ct->lim.phi ); pj_dalloc(ct); pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); return 0; } ct->cvs = NULL; /* -------------------------------------------------------------------- */ /* Create a new gridinfo for this if we aren't processing the */ /* 1st subfile, and initialize our grid info. */ /* -------------------------------------------------------------------- */ if( subfile == 0 ) gi = gilist; else { gi = (PJ_GRIDINFO *) pj_calloc(1, sizeof(PJ_GRIDINFO)); if (!gi) { pj_dalloc(ct); pj_gridinfo_free(ctx, gilist); pj_ctx_set_errno(ctx, ENOMEM); return 0; } gi->gridname = pj_strdup( gilist->gridname ); gi->filename = pj_strdup( gilist->filename ); if (!gi->gridname || !gi->filename) { pj_gridinfo_free(ctx, gi); pj_dalloc(ct); pj_gridinfo_free(ctx, gilist); pj_ctx_set_errno(ctx, ENOMEM); return 0; } gi->next = NULL; } gi->must_swap = must_swap; gi->ct = ct; gi->format = "ntv2"; gi->grid_offset = pj_ctx_ftell( ctx, fid ); /* -------------------------------------------------------------------- */ /* Attach to the correct list or sublist. */ /* -------------------------------------------------------------------- */ if( strncmp((const char *)header+24,"NONE",4) == 0 ) { if( gi != gilist ) { PJ_GRIDINFO *lnk; for( lnk = gilist; lnk->next != NULL; lnk = lnk->next ) {} lnk->next = gi; } } else { PJ_GRIDINFO *lnk; PJ_GRIDINFO *gp = gridinfo_parent(gilist, (const char*)header+24,8); if( gp == NULL ) { pj_log( ctx, PJ_LOG_ERROR, "pj_gridinfo_init_ntv2(): " "failed to find parent %8.8s for %s.", (const char *) header+24, gi->ct->id ); for( lnk = gilist; lnk->next != NULL; lnk = lnk->next ) {} lnk->next = gi; } else { if( gp->child == NULL ) { gp->child = gi; } else { for( lnk = gp->child; lnk->next != NULL; lnk = lnk->next ) {} lnk->next = gi; } } } /* -------------------------------------------------------------------- */ /* Seek past the data. */ /* -------------------------------------------------------------------- */ pj_ctx_fseek( ctx, fid, gs_count * 16, SEEK_CUR ); } return 1; }
int pj_gridinfo_load( projCtx ctx, PJ_GRIDINFO *gi ) { struct CTABLE ct_tmp; if( gi == NULL || gi->ct == NULL ) return 0; pj_acquire_lock(); if( gi->ct->cvs != NULL ) { pj_release_lock(); return 1; } memcpy(&ct_tmp, gi->ct, sizeof(struct CTABLE)); /* -------------------------------------------------------------------- */ /* Original platform specific CTable format. */ /* -------------------------------------------------------------------- */ if( strcmp(gi->format,"ctable") == 0 ) { PAFile fid; int result; fid = pj_open_lib( ctx, gi->filename, "rb" ); if( fid == NULL ) { pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); pj_release_lock(); return 0; } result = nad_ctable_load( ctx, &ct_tmp, fid ); pj_ctx_fclose( ctx, fid ); gi->ct->cvs = ct_tmp.cvs; pj_release_lock(); return result; } /* -------------------------------------------------------------------- */ /* CTable2 format. */ /* -------------------------------------------------------------------- */ else if( strcmp(gi->format,"ctable2") == 0 ) { PAFile fid; int result; fid = pj_open_lib( ctx, gi->filename, "rb" ); if( fid == NULL ) { pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); pj_release_lock(); return 0; } result = nad_ctable2_load( ctx, &ct_tmp, fid ); pj_ctx_fclose( ctx, fid ); gi->ct->cvs = ct_tmp.cvs; pj_release_lock(); return result; } /* -------------------------------------------------------------------- */ /* NTv1 format. */ /* We process one line at a time. Note that the array storage */ /* direction (e-w) is different in the NTv1 file and what */ /* the CTABLE is supposed to have. The phi/lam are also */ /* reversed, and we have to be aware of byte swapping. */ /* -------------------------------------------------------------------- */ else if( strcmp(gi->format,"ntv1") == 0 ) { double *row_buf; int row; PAFile fid; fid = pj_open_lib( ctx, gi->filename, "rb" ); if( fid == NULL ) { pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); pj_release_lock(); return 0; } pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET ); row_buf = (double *) pj_malloc(gi->ct->lim.lam * sizeof(double) * 2); ct_tmp.cvs = (FLP *) pj_malloc(gi->ct->lim.lam*gi->ct->lim.phi*sizeof(FLP)); if( row_buf == NULL || ct_tmp.cvs == NULL ) { pj_dalloc( row_buf ); pj_dalloc( ct_tmp.cvs ); pj_ctx_set_errno( ctx, ENOMEM ); pj_release_lock(); return 0; } for( row = 0; row < gi->ct->lim.phi; row++ ) { int i; FLP *cvs; double *diff_seconds; if( pj_ctx_fread( ctx, row_buf, sizeof(double), gi->ct->lim.lam * 2, fid ) != (size_t)( 2 * gi->ct->lim.lam ) ) { pj_dalloc( row_buf ); pj_dalloc( ct_tmp.cvs ); pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); pj_release_lock(); return 0; } if( IS_LSB ) swap_words( (unsigned char *) row_buf, 8, gi->ct->lim.lam*2 ); /* convert seconds to radians */ diff_seconds = row_buf; for( i = 0; i < gi->ct->lim.lam; i++ ) { cvs = ct_tmp.cvs + (row) * gi->ct->lim.lam + (gi->ct->lim.lam - i - 1); cvs->phi = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); cvs->lam = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); } } pj_dalloc( row_buf ); pj_ctx_fclose( ctx, fid ); gi->ct->cvs = ct_tmp.cvs; pj_release_lock(); return 1; } /* -------------------------------------------------------------------- */ /* NTv2 format. */ /* We process one line at a time. Note that the array storage */ /* direction (e-w) is different in the NTv2 file and what */ /* the CTABLE is supposed to have. The phi/lam are also */ /* reversed, and we have to be aware of byte swapping. */ /* -------------------------------------------------------------------- */ else if( strcmp(gi->format,"ntv2") == 0 ) { float *row_buf; int row; PAFile fid; pj_log( ctx, PJ_LOG_DEBUG_MINOR, "NTv2 - loading grid %s", gi->ct->id ); fid = pj_open_lib( ctx, gi->filename, "rb" ); if( fid == NULL ) { pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); pj_release_lock(); return 0; } pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET ); row_buf = (float *) pj_malloc(gi->ct->lim.lam * sizeof(float) * 4); ct_tmp.cvs = (FLP *) pj_malloc(gi->ct->lim.lam*gi->ct->lim.phi*sizeof(FLP)); if( row_buf == NULL || ct_tmp.cvs == NULL ) { pj_dalloc( row_buf ); pj_dalloc( ct_tmp.cvs ); pj_ctx_set_errno( ctx, ENOMEM ); pj_release_lock(); return 0; } for( row = 0; row < gi->ct->lim.phi; row++ ) { int i; FLP *cvs; float *diff_seconds; if( pj_ctx_fread( ctx, row_buf, sizeof(float), gi->ct->lim.lam*4, fid ) != (size_t)( 4 * gi->ct->lim.lam ) ) { pj_dalloc( row_buf ); pj_dalloc( ct_tmp.cvs ); pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); pj_release_lock(); return 0; } if( gi->must_swap ) swap_words( (unsigned char *) row_buf, 4, gi->ct->lim.lam*4 ); /* convert seconds to radians */ diff_seconds = row_buf; for( i = 0; i < gi->ct->lim.lam; i++ ) { cvs = ct_tmp.cvs + (row) * gi->ct->lim.lam + (gi->ct->lim.lam - i - 1); cvs->phi = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); cvs->lam = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); diff_seconds += 2; /* skip accuracy values */ } } pj_dalloc( row_buf ); pj_ctx_fclose( ctx, fid ); gi->ct->cvs = ct_tmp.cvs; pj_release_lock(); return 1; } /* -------------------------------------------------------------------- */ /* GTX format. */ /* -------------------------------------------------------------------- */ else if( strcmp(gi->format,"gtx") == 0 ) { int words = gi->ct->lim.lam * gi->ct->lim.phi; PAFile fid; fid = pj_open_lib( ctx, gi->filename, "rb" ); if( fid == NULL ) { pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); pj_release_lock(); return 0; } pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET ); ct_tmp.cvs = (FLP *) pj_malloc(words*sizeof(float)); if( ct_tmp.cvs == NULL ) { pj_ctx_set_errno( ctx, ENOMEM ); pj_release_lock(); return 0; } if( pj_ctx_fread( ctx, ct_tmp.cvs, sizeof(float), words, fid ) != (size_t)words ) { pj_dalloc( ct_tmp.cvs ); pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); pj_release_lock(); return 0; } if( IS_LSB ) swap_words( (unsigned char *) ct_tmp.cvs, 4, words ); pj_ctx_fclose( ctx, fid ); gi->ct->cvs = ct_tmp.cvs; pj_release_lock(); return 1; } else { pj_release_lock(); return 0; } }
int pj_datum_set(projCtx ctx, paralist *pl, PJ *projdef) { const char *name, *towgs84, *nadgrids, *catalog; projdef->datum_type = PJD_UNKNOWN; /* -------------------------------------------------------------------- */ /* Is there a datum definition in the parameters list? If so, */ /* add the defining values to the parameter list. Note that */ /* this will append the ellipse definition as well as the */ /* towgs84= and related parameters. It should also be pointed */ /* out that the addition is permanent rather than temporary */ /* like most other keyword expansion so that the ellipse */ /* definition will last into the pj_ell_set() function called */ /* after this one. */ /* -------------------------------------------------------------------- */ if( (name = pj_param(ctx, pl,"sdatum").s) != NULL ) { paralist *curr; const char *s; int i; /* find the end of the list, so we can add to it */ for (curr = pl; curr && curr->next ; curr = curr->next) {} /* find the datum definition */ for (i = 0; (s = pj_datums[i].id) && strcmp(name, s) ; ++i) {} if (!s) { pj_ctx_set_errno(ctx, -9); return 1; } if( pj_datums[i].ellipse_id && strlen(pj_datums[i].ellipse_id) > 0 ) { char entry[100]; strcpy( entry, "ellps=" ); strncat( entry, pj_datums[i].ellipse_id, 80 ); curr = curr->next = pj_mkparam(entry); } if( pj_datums[i].defn && strlen(pj_datums[i].defn) > 0 ) curr = curr->next = pj_mkparam(pj_datums[i].defn); } /* -------------------------------------------------------------------- */ /* Check for nadgrids parameter. */ /* -------------------------------------------------------------------- */ if( (nadgrids = pj_param(ctx, pl,"snadgrids").s) != NULL ) { /* We don't actually save the value separately. It will continue to exist int he param list for use in pj_apply_gridshift.c */ projdef->datum_type = PJD_GRIDSHIFT; } /* -------------------------------------------------------------------- */ /* Check for grid catalog parameter, and optional date. */ /* -------------------------------------------------------------------- */ else if( (catalog = pj_param(ctx, pl,"scatalog").s) != NULL ) { const char *date; projdef->datum_type = PJD_GRIDSHIFT; projdef->catalog_name = strdup(catalog); date = pj_param(ctx, pl, "sdate").s; if( date != NULL) projdef->datum_date = pj_gc_parsedate( ctx, date); } /* -------------------------------------------------------------------- */ /* Check for towgs84 parameter. */ /* -------------------------------------------------------------------- */ else if( (towgs84 = pj_param(ctx, pl,"stowgs84").s) != NULL ) { int parm_count = 0; const char *s; memset( projdef->datum_params, 0, sizeof(double) * 7); /* parse out the parameters */ s = towgs84; for( s = towgs84; *s != '\0' && parm_count < 7; ) { projdef->datum_params[parm_count++] = atof(s); while( *s != '\0' && *s != ',' ) s++; if( *s == ',' ) s++; } if( projdef->datum_params[3] != 0.0 || projdef->datum_params[4] != 0.0 || projdef->datum_params[5] != 0.0 || projdef->datum_params[6] != 0.0 ) { projdef->datum_type = PJD_7PARAM; /* transform from arc seconds to radians */ projdef->datum_params[3] *= SEC_TO_RAD; projdef->datum_params[4] *= SEC_TO_RAD; projdef->datum_params[5] *= SEC_TO_RAD; /* transform from parts per million to scaling factor */ projdef->datum_params[6] = (projdef->datum_params[6]/1000000.0) + 1; } else projdef->datum_type = PJD_3PARAM; /* Note that pj_init() will later switch datum_type to PJD_WGS84 if shifts are all zero, and ellipsoid is WGS84 or GRS80 */ } return 0; }
struct CTABLE *nad_ctable2_init( projCtx ctx, FILE * fid ) { struct CTABLE *ct; int id_end; char header[160]; if( fread( header, sizeof(header), 1, fid ) != 1 ) { pj_ctx_set_errno( ctx, -38 ); return NULL; } if( !IS_LSB ) { swap_words( header + 96, 8, 4 ); swap_words( header + 128, 4, 2 ); } if( strncmp(header,"CTABLE V2",9) != 0 ) { pj_log( ctx, PJ_LOG_ERROR, "ctable2 - wrong header!" ); pj_ctx_set_errno( ctx, -38 ); return NULL; } /* read the table header */ ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); if( ct == NULL ) { pj_ctx_set_errno( ctx, -38 ); return NULL; } memcpy( ct->id, header + 16, 80 ); memcpy( &ct->ll.lam, header + 96, 8 ); memcpy( &ct->ll.phi, header + 104, 8 ); memcpy( &ct->del.lam, header + 112, 8 ); memcpy( &ct->del.phi, header + 120, 8 ); memcpy( &ct->lim.lam, header + 128, 4 ); memcpy( &ct->lim.phi, header + 132, 4 ); /* do some minimal validation to ensure the structure isn't corrupt */ if( ct->lim.lam < 1 || ct->lim.lam > 100000 || ct->lim.phi < 1 || ct->lim.phi > 100000 ) { pj_ctx_set_errno( ctx, -38 ); return NULL; } /* trim white space and newlines off id */ for( id_end = strlen(ct->id)-1; id_end > 0; id_end-- ) { if( ct->id[id_end] == '\n' || ct->id[id_end] == ' ' ) ct->id[id_end] = '\0'; else break; } ct->cvs = NULL; return ct; }
PJ *pj_latlong_from_proj( PJ *pj_in ) { char defn[512]; int got_datum = FALSE; pj_errno = 0; strcpy( defn, "+proj=latlong" ); if( pj_param(pj_in->ctx, pj_in->params, "tdatum").i ) { got_datum = TRUE; sprintf( defn+strlen(defn), " +datum=%s", pj_param(pj_in->ctx, pj_in->params,"sdatum").s ); } else if( pj_param(pj_in->ctx, pj_in->params, "tellps").i ) { sprintf( defn+strlen(defn), " +ellps=%s", pj_param(pj_in->ctx, pj_in->params,"sellps").s ); } else if( pj_param(pj_in->ctx,pj_in->params, "ta").i ) { sprintf( defn+strlen(defn), " +a=%s", pj_param(pj_in->ctx,pj_in->params,"sa").s ); if( pj_param(pj_in->ctx,pj_in->params, "tb").i ) sprintf( defn+strlen(defn), " +b=%s", pj_param(pj_in->ctx,pj_in->params,"sb").s ); else if( pj_param(pj_in->ctx,pj_in->params, "tes").i ) sprintf( defn+strlen(defn), " +es=%s", pj_param(pj_in->ctx,pj_in->params,"ses").s ); else if( pj_param(pj_in->ctx,pj_in->params, "tf").i ) sprintf( defn+strlen(defn), " +f=%s", pj_param(pj_in->ctx,pj_in->params,"sf").s ); else sprintf( defn+strlen(defn), " +es=%.16g", pj_in->es ); } else { pj_ctx_set_errno( pj_in->ctx, -13 ); return NULL; } if( !got_datum ) { if( pj_param(pj_in->ctx,pj_in->params, "ttowgs84").i ) sprintf( defn+strlen(defn), " +towgs84=%s", pj_param(pj_in->ctx,pj_in->params,"stowgs84").s ); if( pj_param(pj_in->ctx,pj_in->params, "tnadgrids").i ) sprintf( defn+strlen(defn), " +nadgrids=%s", pj_param(pj_in->ctx,pj_in->params,"snadgrids").s ); } /* copy over some other information related to ellipsoid */ if( pj_param(pj_in->ctx,pj_in->params, "tR").i ) sprintf( defn+strlen(defn), " +R=%s", pj_param(pj_in->ctx,pj_in->params,"sR").s ); if( pj_param(pj_in->ctx,pj_in->params, "tR_A").i ) sprintf( defn+strlen(defn), " +R_A" ); if( pj_param(pj_in->ctx,pj_in->params, "tR_V").i ) sprintf( defn+strlen(defn), " +R_V" ); if( pj_param(pj_in->ctx,pj_in->params, "tR_a").i ) sprintf( defn+strlen(defn), " +R_a" ); if( pj_param(pj_in->ctx,pj_in->params, "tR_lat_a").i ) sprintf( defn+strlen(defn), " +R_lat_a=%s", pj_param(pj_in->ctx,pj_in->params,"sR_lat_a").s ); if( pj_param(pj_in->ctx,pj_in->params, "tR_lat_g").i ) sprintf( defn+strlen(defn), " +R_lat_g=%s", pj_param(pj_in->ctx,pj_in->params,"sR_lat_g").s ); /* copy over prime meridian */ if( pj_param(pj_in->ctx,pj_in->params, "tpm").i ) sprintf( defn+strlen(defn), " +pm=%s", pj_param(pj_in->ctx,pj_in->params,"spm").s ); return pj_init_plus_ctx( pj_in->ctx, defn ); }
int pj_gc_apply_gridshift( PJ *defn, int inverse, long point_count, int point_offset, double *x, double *y, double *z ) { int i; if( defn->catalog == NULL ) { defn->catalog = pj_gc_findcatalog( defn->ctx, defn->catalog_name ); if( defn->catalog == NULL ) return defn->ctx->last_errno; } defn->ctx->last_errno = 0; for( i = 0; i < point_count; i++ ) { long io = i * point_offset; LP input, output_after, output_before; double mix_ratio; PJ_GRIDINFO *gi; input.phi = y[io]; input.lam = x[io]; /* make sure we have appropriate "after" shift file available */ if( defn->last_after_grid == NULL || input.lam < defn->last_after_region.ll_long || input.lam > defn->last_after_region.ur_long || input.phi < defn->last_after_region.ll_lat || input.phi > defn->last_after_region.ll_lat ) { defn->last_after_grid = pj_gc_findgrid( defn->ctx, defn->catalog, 1, input, defn->datum_date, &(defn->last_after_region), &(defn->last_after_date)); } gi = defn->last_after_grid; assert( gi->child == NULL ); /* load the grid shift info if we don't have it. */ if( gi->ct->cvs == NULL && !pj_gridinfo_load( defn->ctx, gi ) ) { pj_ctx_set_errno( defn->ctx, -38 ); return -38; } output_after = nad_cvt( input, inverse, gi->ct ); if( output_after.lam == HUGE_VAL ) { if( defn->ctx->debug_level >= PJ_LOG_DEBUG_MAJOR ) { pj_log( defn->ctx, PJ_LOG_DEBUG_MAJOR, "pj_apply_gridshift(): failed to find a grid shift table for\n" " location (%.7fdW,%.7fdN)", x[io] * RAD_TO_DEG, y[io] * RAD_TO_DEG ); } continue; } if( defn->datum_date == 0.0 ) { y[io] = output_after.phi; x[io] = output_after.lam; continue; } /* make sure we have appropriate "before" shift file available */ if( defn->last_before_grid == NULL || input.lam < defn->last_before_region.ll_long || input.lam > defn->last_before_region.ur_long || input.phi < defn->last_before_region.ll_lat || input.phi > defn->last_before_region.ll_lat ) { defn->last_before_grid = pj_gc_findgrid( defn->ctx, defn->catalog, 0, input, defn->datum_date, &(defn->last_before_region), &(defn->last_before_date)); } gi = defn->last_before_grid; assert( gi->child == NULL ); /* load the grid shift info if we don't have it. */ if( gi->ct->cvs == NULL && !pj_gridinfo_load( defn->ctx, gi ) ) { pj_ctx_set_errno( defn->ctx, -38 ); return -38; } output_before = nad_cvt( input, inverse, gi->ct ); if( output_before.lam == HUGE_VAL ) { if( defn->ctx->debug_level >= PJ_LOG_DEBUG_MAJOR ) { pj_log( defn->ctx, PJ_LOG_DEBUG_MAJOR, "pj_apply_gridshift(): failed to find a grid shift table for\n" " location (%.7fdW,%.7fdN)", x[io] * RAD_TO_DEG, y[io] * RAD_TO_DEG ); } continue; } mix_ratio = (defn->datum_date - defn->last_before_date) / (defn->last_after_date - defn->last_before_date); y[io] = mix_ratio * output_after.phi + (1.0-mix_ratio) * output_before.phi; x[io] = mix_ratio * output_after.lam + (1.0-mix_ratio) * output_before.lam; } return 0; }