int pj_apply_gridshift_2( PJ *defn, int inverse, long point_count, int point_offset, double *x, double *y, double *z ) { if( defn->gridlist == NULL ) { defn->gridlist = pj_gridlist_from_nadgrids( pj_get_ctx( defn ), pj_param(defn->ctx, defn->params,"snadgrids").s, &(defn->gridlist_count) ); if( defn->gridlist == NULL || defn->gridlist_count == 0 ) return defn->ctx->last_errno; } return pj_apply_gridshift_3( pj_get_ctx( defn ), defn->gridlist, defn->gridlist_count, inverse, point_count, point_offset, x, y, z ); }
int proj_errno_set (const PJ *P, int err) { /****************************************************************************** Set context-errno, bubble it up to the thread local errno, return err ******************************************************************************/ /* Use proj_errno_reset to explicitly clear the error status */ if (0==err) return 0; /* For P==0 err goes to the default context */ proj_context_errno_set (pj_get_ctx ((PJ *) P), err); errno = err; return err; }
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 proj_errno (const PJ *P) { /****************************************************************************** Read an error level from the context of a PJ. ******************************************************************************/ return pj_ctx_get_errno (pj_get_ctx ((PJ *) P)); }
int pj_transform( PJ *srcdefn, PJ *dstdefn, long point_count, int point_offset, double *x, double *y, double *z ) { long i; int err; srcdefn->ctx->last_errno = 0; dstdefn->ctx->last_errno = 0; if( point_offset == 0 ) point_offset = 1; /* -------------------------------------------------------------------- */ /* Transform unusual input coordinate axis orientation to */ /* standard form if needed. */ /* -------------------------------------------------------------------- */ if( strcmp(srcdefn->axis,"enu") != 0 ) { int err; err = pj_adjust_axis( srcdefn->ctx, srcdefn->axis, 0, point_count, point_offset, x, y, z ); if( err != 0 ) return err; } /* -------------------------------------------------------------------- */ /* Transform Z to meters if it isn't already. */ /* -------------------------------------------------------------------- */ if( srcdefn->vto_meter != 1.0 && z != NULL ) { for( i = 0; i < point_count; i++ ) z[point_offset*i] *= srcdefn->vto_meter; } /* -------------------------------------------------------------------- */ /* Transform geocentric source coordinates to lat/long. */ /* -------------------------------------------------------------------- */ if( srcdefn->is_geocent ) { if( z == NULL ) { pj_ctx_set_errno( pj_get_ctx(srcdefn), PJD_ERR_GEOCENTRIC); return PJD_ERR_GEOCENTRIC; } if( srcdefn->to_meter != 1.0 ) { for( i = 0; i < point_count; i++ ) { if( x[point_offset*i] != HUGE_VAL ) { x[point_offset*i] *= srcdefn->to_meter; y[point_offset*i] *= srcdefn->to_meter; } } } err = pj_geocentric_to_geodetic( srcdefn->a_orig, srcdefn->es_orig, point_count, point_offset, x, y, z ); if( err != 0 ) return err; } /* -------------------------------------------------------------------- */ /* Transform source points to lat/long, if they aren't */ /* already. */ /* -------------------------------------------------------------------- */ else if( !srcdefn->is_latlong ) { if( srcdefn->inv == NULL ) { pj_ctx_set_errno( pj_get_ctx(srcdefn), -17 ); pj_log( pj_get_ctx(srcdefn), PJ_LOG_ERROR, "pj_transform(): source projection not invertable" ); return -17; } for( i = 0; i < point_count; i++ ) { XY projected_loc; LP geodetic_loc; projected_loc.u = x[point_offset*i]; projected_loc.v = y[point_offset*i]; if( projected_loc.u == HUGE_VAL ) continue; geodetic_loc = pj_inv( projected_loc, srcdefn ); if( srcdefn->ctx->last_errno != 0 ) { if( (srcdefn->ctx->last_errno != 33 /*EDOM*/ && srcdefn->ctx->last_errno != 34 /*ERANGE*/ ) && (srcdefn->ctx->last_errno > 0 || srcdefn->ctx->last_errno < -44 || point_count == 1 || transient_error[-srcdefn->ctx->last_errno] == 0 ) ) return srcdefn->ctx->last_errno; else { geodetic_loc.u = HUGE_VAL; geodetic_loc.v = HUGE_VAL; } } x[point_offset*i] = geodetic_loc.u; y[point_offset*i] = geodetic_loc.v; } } /* -------------------------------------------------------------------- */ /* But if they are already lat long, adjust for the prime */ /* meridian if there is one in effect. */ /* -------------------------------------------------------------------- */ if( srcdefn->from_greenwich != 0.0 ) { for( i = 0; i < point_count; i++ ) { if( x[point_offset*i] != HUGE_VAL ) x[point_offset*i] += srcdefn->from_greenwich; } } /* -------------------------------------------------------------------- */ /* Do we need to translate from geoid to ellipsoidal vertical */ /* datum? */ /* -------------------------------------------------------------------- */ if( srcdefn->has_geoid_vgrids ) { if( pj_apply_vgridshift( srcdefn, "sgeoidgrids", &(srcdefn->vgridlist_geoid), &(srcdefn->vgridlist_geoid_count), 0, point_count, point_offset, x, y, z ) != 0 ) return pj_ctx_get_errno(srcdefn->ctx); } /* -------------------------------------------------------------------- */ /* Convert datums if needed, and possible. */ /* -------------------------------------------------------------------- */ if( pj_datum_transform( srcdefn, dstdefn, point_count, point_offset, x, y, z ) != 0 ) { if( srcdefn->ctx->last_errno != 0 ) return srcdefn->ctx->last_errno; else return dstdefn->ctx->last_errno; } /* -------------------------------------------------------------------- */ /* Do we need to translate from geoid to ellipsoidal vertical */ /* datum? */ /* -------------------------------------------------------------------- */ if( dstdefn->has_geoid_vgrids ) { if( pj_apply_vgridshift( dstdefn, "sgeoidgrids", &(dstdefn->vgridlist_geoid), &(dstdefn->vgridlist_geoid_count), 1, point_count, point_offset, x, y, z ) != 0 ) return dstdefn->ctx->last_errno; } /* -------------------------------------------------------------------- */ /* But if they are staying lat long, adjust for the prime */ /* meridian if there is one in effect. */ /* -------------------------------------------------------------------- */ if( dstdefn->from_greenwich != 0.0 ) { for( i = 0; i < point_count; i++ ) { if( x[point_offset*i] != HUGE_VAL ) x[point_offset*i] -= dstdefn->from_greenwich; } } /* -------------------------------------------------------------------- */ /* Transform destination latlong to geocentric if required. */ /* -------------------------------------------------------------------- */ if( dstdefn->is_geocent ) { if( z == NULL ) { pj_ctx_set_errno( dstdefn->ctx, PJD_ERR_GEOCENTRIC ); return PJD_ERR_GEOCENTRIC; } pj_geodetic_to_geocentric( dstdefn->a_orig, dstdefn->es_orig, point_count, point_offset, x, y, z ); if( dstdefn->fr_meter != 1.0 ) { for( i = 0; i < point_count; i++ ) { if( x[point_offset*i] != HUGE_VAL ) { x[point_offset*i] *= dstdefn->fr_meter; y[point_offset*i] *= dstdefn->fr_meter; } } } } /* -------------------------------------------------------------------- */ /* Transform destination points to projection coordinates, if */ /* desired. */ /* -------------------------------------------------------------------- */ else if( !dstdefn->is_latlong ) { for( i = 0; i < point_count; i++ ) { XY projected_loc; LP geodetic_loc; geodetic_loc.u = x[point_offset*i]; geodetic_loc.v = y[point_offset*i]; if( geodetic_loc.u == HUGE_VAL ) continue; projected_loc = pj_fwd( geodetic_loc, dstdefn ); if( dstdefn->ctx->last_errno != 0 ) { if( (dstdefn->ctx->last_errno != 33 /*EDOM*/ && dstdefn->ctx->last_errno != 34 /*ERANGE*/ ) && (dstdefn->ctx->last_errno > 0 || dstdefn->ctx->last_errno < -44 || point_count == 1 || transient_error[-dstdefn->ctx->last_errno] == 0 ) ) return dstdefn->ctx->last_errno; else { projected_loc.u = HUGE_VAL; projected_loc.v = HUGE_VAL; } } x[point_offset*i] = projected_loc.u; y[point_offset*i] = projected_loc.v; } } /* -------------------------------------------------------------------- */ /* If a wrapping center other than 0 is provided, rewrap around */ /* the suggested center (for latlong coordinate systems only). */ /* -------------------------------------------------------------------- */ else if( dstdefn->is_latlong && dstdefn->is_long_wrap_set ) { for( i = 0; i < point_count; i++ ) { if( x[point_offset*i] == HUGE_VAL ) continue; while( x[point_offset*i] < dstdefn->long_wrap_center - PI ) x[point_offset*i] += TWOPI; while( x[point_offset*i] > dstdefn->long_wrap_center + PI ) x[point_offset*i] -= TWOPI; } } /* -------------------------------------------------------------------- */ /* Transform Z from meters if needed. */ /* -------------------------------------------------------------------- */ if( dstdefn->vto_meter != 1.0 && z != NULL ) { for( i = 0; i < point_count; i++ ) z[point_offset*i] *= dstdefn->vfr_meter; } /* -------------------------------------------------------------------- */ /* Transform normalized axes into unusual output coordinate axis */ /* orientation if needed. */ /* -------------------------------------------------------------------- */ if( strcmp(dstdefn->axis,"enu") != 0 ) { int err; err = pj_adjust_axis( dstdefn->ctx, dstdefn->axis, 1, point_count, point_offset, x, y, z ); if( err != 0 ) return err; } return 0; }
static double read_vgrid_value( PJ *defn, LP input, int *gridlist_count_p, PJ_GRIDINFO **tables, struct CTABLE *ct) { int itable = 0; double value = HUGE_VAL; double grid_x, grid_y; long grid_ix, grid_iy; long grid_ix2, grid_iy2; float *cvs; /* do not deal with NaN coordinates */ /* cppcheck-suppress duplicateExpression */ if( isnan(input.phi) || isnan(input.lam) ) itable = *gridlist_count_p; /* keep trying till we find a table that works */ for ( ; itable < *gridlist_count_p; itable++ ) { PJ_GRIDINFO *gi = tables[itable]; ct = gi->ct; /* skip tables that don't match our point at all. */ if( ct->ll.phi > input.phi || ct->ll.lam > input.lam || ct->ll.phi + (ct->lim.phi-1) * ct->del.phi < input.phi || ct->ll.lam + (ct->lim.lam-1) * ct->del.lam < input.lam ) continue; /* If we have child nodes, check to see if any of them apply. */ while( gi->child != NULL ) { PJ_GRIDINFO *child; for( child = gi->child; child != NULL; child = child->next ) { struct CTABLE *ct1 = child->ct; if( ct1->ll.phi > input.phi || ct1->ll.lam > input.lam || ct1->ll.phi+(ct1->lim.phi-1)*ct1->del.phi < input.phi || ct1->ll.lam+(ct1->lim.lam-1)*ct1->del.lam < input.lam) continue; break; } /* we didn't find a more refined child node to use, so go with current grid */ if( child == NULL ) { break; } /* Otherwise let's try for childrens children .. */ gi = child; ct = child->ct; } /* load the grid shift info if we don't have it. */ if( ct->cvs == NULL && !pj_gridinfo_load( pj_get_ctx(defn), gi ) ) { pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); return PJD_ERR_FAILED_TO_LOAD_GRID; } /* Interpolation a location within the grid */ grid_x = (input.lam - ct->ll.lam) / ct->del.lam; grid_y = (input.phi - ct->ll.phi) / ct->del.phi; grid_ix = lround(floor(grid_x)); grid_iy = lround(floor(grid_y)); grid_x -= grid_ix; grid_y -= grid_iy; grid_ix2 = grid_ix + 1; if( grid_ix2 >= ct->lim.lam ) grid_ix2 = ct->lim.lam - 1; grid_iy2 = grid_iy + 1; if( grid_iy2 >= ct->lim.phi ) grid_iy2 = ct->lim.phi - 1; cvs = (float *) ct->cvs; { float value_a = cvs[grid_ix + grid_iy * ct->lim.lam]; float value_b = cvs[grid_ix2 + grid_iy * ct->lim.lam]; float value_c = cvs[grid_ix + grid_iy2 * ct->lim.lam]; float value_d = cvs[grid_ix2 + grid_iy2 * ct->lim.lam]; double total_weight = 0.0; int n_weights = 0; value = 0.0f; if( !is_nodata(value_a) ) { double weight = (1.0-grid_x) * (1.0-grid_y); value += value_a * weight; total_weight += weight; n_weights ++; } if( !is_nodata(value_b) ) { double weight = (grid_x) * (1.0-grid_y); value += value_b * weight; total_weight += weight; n_weights ++; } if( !is_nodata(value_c) ) { double weight = (1.0-grid_x) * (grid_y); value += value_c * weight; total_weight += weight; n_weights ++; } if( !is_nodata(value_d) ) { double weight = (grid_x) * (grid_y); value += value_d * weight; total_weight += weight; n_weights ++; } if( n_weights == 0 ) value = HUGE_VAL; else if( n_weights != 4 ) value /= total_weight; } } return value; }
int pj_apply_vgridshift( PJ *defn, const char *listname, PJ_GRIDINFO ***gridlist_p, int *gridlist_count_p, int inverse, long point_count, int point_offset, double *x, double *y, double *z ) { int i; static int debug_count = 0; PJ_GRIDINFO **tables; struct CTABLE ct; if( *gridlist_p == NULL ) { *gridlist_p = pj_gridlist_from_nadgrids( pj_get_ctx(defn), pj_param(defn->ctx,defn->params,listname).s, gridlist_count_p ); if( *gridlist_p == NULL || *gridlist_count_p == 0 ) return defn->ctx->last_errno; } if( *gridlist_count_p == 0 ) { pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return PJD_ERR_FAILED_TO_LOAD_GRID; } tables = *gridlist_p; defn->ctx->last_errno = 0; for( i = 0; i < point_count; i++ ) { double value; long io = i * point_offset; LP input; input.phi = y[io]; input.lam = x[io]; value = read_vgrid_value(defn, input, gridlist_count_p, tables, &ct); if( inverse ) z[io] -= value; else z[io] += value; if( value != HUGE_VAL ) { if( debug_count++ < 20 ) { proj_log_trace(defn, "pj_apply_gridshift(): used %s", ct.id); break; } } if( value == HUGE_VAL ) { int itable; char gridlist[3000]; proj_log_debug(defn, "pj_apply_vgridshift(): failed to find a grid shift table for\n" " location (%.7fdW,%.7fdN)", x[io] * RAD_TO_DEG, y[io] * RAD_TO_DEG ); gridlist[0] = '\0'; for( itable = 0; itable < *gridlist_count_p; itable++ ) { PJ_GRIDINFO *gi = tables[itable]; if( strlen(gridlist) + strlen(gi->gridname) > sizeof(gridlist)-100 ) { strcat( gridlist, "..." ); break; } if( itable == 0 ) sprintf( gridlist, " tried: %s", gi->gridname ); else sprintf( gridlist+strlen(gridlist), ",%s", gi->gridname ); } proj_log_debug(defn, "%s", gridlist); pj_ctx_set_errno( defn->ctx, PJD_ERR_GRID_AREA ); return PJD_ERR_GRID_AREA; } } return 0; }
PJ *PROJECTION(ob_tran) { double phip; char *name; ARGS args; PJ *R; /* projection to rotate */ struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return destructor(P, ENOMEM); P->opaque = Q; P->destructor = destructor; /* get name of projection to be translated */ if (!(name = pj_param(P->ctx, P->params, "so_proj").s)) return destructor(P, PJD_ERR_NO_ROTATION_PROJ); /* avoid endless recursion */ if( strcmp(name, "ob_tran") == 0 ) return destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); /* Create the target projection object to rotate */ args = ob_tran_target_params (P->params); R = pj_init_ctx (pj_get_ctx(P), args.argc, args.argv); pj_dealloc (args.argv); if (nullptr==R) return destructor (P, PJD_ERR_UNKNOWN_PROJECTION_ID); Q->link = R; if (pj_param(P->ctx, P->params, "to_alpha").i) { double lamc, phic, alpha; lamc = pj_param(P->ctx, P->params, "ro_lon_c").f; phic = pj_param(P->ctx, P->params, "ro_lat_c").f; alpha = pj_param(P->ctx, P->params, "ro_alpha").f; if (fabs(fabs(phic) - M_HALFPI) <= TOL) return destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); Q->lamp = lamc + aatan2(-cos(alpha), -sin(alpha) * sin(phic)); phip = aasin(P->ctx,cos(phic) * sin(alpha)); } else if (pj_param(P->ctx, P->params, "to_lat_p").i) { /* specified new pole */ Q->lamp = pj_param(P->ctx, P->params, "ro_lon_p").f; phip = pj_param(P->ctx, P->params, "ro_lat_p").f; } else { /* specified new "equator" points */ double lam1, lam2, phi1, phi2, con; lam1 = pj_param(P->ctx, P->params, "ro_lon_1").f; phi1 = pj_param(P->ctx, P->params, "ro_lat_1").f; lam2 = pj_param(P->ctx, P->params, "ro_lon_2").f; phi2 = pj_param(P->ctx, P->params, "ro_lat_2").f; if (fabs(phi1 - phi2) <= TOL || (con = fabs(phi1)) <= TOL || fabs(con - M_HALFPI) <= TOL || fabs(fabs(phi2) - M_HALFPI) <= TOL) return destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); Q->lamp = atan2(cos(phi1) * sin(phi2) * cos(lam1) - sin(phi1) * cos(phi2) * cos(lam2), sin(phi1) * cos(phi2) * sin(lam2) - cos(phi1) * sin(phi2) * sin(lam1)); phip = atan(-cos(Q->lamp - lam1) / tan(phi1)); } if (fabs(phip) > TOL) { /* oblique */ Q->cphip = cos(phip); Q->sphip = sin(phip); P->fwd = Q->link->fwd ? o_forward : nullptr; P->inv = Q->link->inv ? o_inverse : nullptr; } else { /* transverse */ P->fwd = Q->link->fwd ? t_forward : nullptr; P->inv = Q->link->inv ? t_inverse : nullptr; } /* Support some rather speculative test cases, where the rotated projection */ /* is actually latlong. We do not want scaling in that case... */ if (Q->link->right==PJ_IO_UNITS_RADIANS) P->right = PJ_IO_UNITS_PROJECTED; return P; }
int pj_apply_vgridshift(PJ *defn, const char *listname, PJ_GRIDINFO ***gridlist_p, int *gridlist_count_p, int inverse, long point_count, int point_offset, double *x, double *y, double *z) { int i; static int debug_count = 0; PJ_GRIDINFO **tables; if (*gridlist_p == NULL) { *gridlist_p = pj_gridlist_from_nadgrids(pj_get_ctx(defn), pj_param(defn->ctx, defn->params, listname).s, gridlist_count_p); if (*gridlist_p == NULL || *gridlist_count_p == 0) return defn->ctx->last_errno; } if (*gridlist_count_p == 0) { pj_ctx_set_errno(defn->ctx, -38); return -38; } tables = *gridlist_p; defn->ctx->last_errno = 0; for (i = 0; i < point_count; i++) { long io = i * point_offset; LP input; int itable; double value = HUGE_VAL; input.phi = y[io]; input.lam = x[io]; /* keep trying till we find a table that works */ for (itable = 0; itable < *gridlist_count_p; itable++) { PJ_GRIDINFO *gi = tables[itable]; struct CTABLE *ct = gi->ct; double grid_x, grid_y; int grid_ix, grid_iy; float *cvs; /* skip tables that don't match our point at all. */ if (ct->ll.phi > input.phi || ct->ll.lam > input.lam || ct->ll.phi + (ct->lim.phi - 1) * ct->del.phi < input.phi || ct->ll.lam + (ct->lim.lam - 1) * ct->del.lam < input.lam) continue; /* If we have child nodes, check to see if any of them apply. */ if (gi->child != NULL) { PJ_GRIDINFO *child; for (child = gi->child; child != NULL; child = child->next) { struct CTABLE *ct1 = child->ct; if (ct1->ll.phi > input.phi || ct1->ll.lam > input.lam || ct1->ll.phi + (ct1->lim.phi - 1) * ct1->del.phi < input.phi || ct1->ll.lam + (ct1->lim.lam - 1) * ct1->del.lam < input.lam) continue; break; } /* we found a more refined child node to use */ if (child != NULL) { gi = child; ct = child->ct; } } /* load the grid shift info if we don't have it. */ if (ct->cvs == NULL && !pj_gridinfo_load(pj_get_ctx(defn), gi)) { pj_ctx_set_errno(defn->ctx, -38); return -38; } /* Interpolation a location within the grid */ grid_x = (input.lam - ct->ll.lam) / ct->del.lam; grid_y = (input.phi - ct->ll.phi) / ct->del.phi; grid_ix = (int)floor(grid_x); grid_iy = (int)floor(grid_y); grid_x -= grid_ix; grid_y -= grid_iy; cvs = (float *)ct->cvs; value = cvs[grid_ix + grid_iy * ct->lim.lam] * (1.0 - grid_x) * (1.0 - grid_y) + cvs[grid_ix + 1 + grid_iy * ct->lim.lam] * (grid_x) * (1.0 - grid_y) + cvs[grid_ix + (grid_iy + 1) * ct->lim.lam] * (1.0 - grid_x) * (grid_y) + cvs[grid_ix + 1 + (grid_iy + 1) * ct->lim.lam] * (grid_x) * (grid_y); if (value > 1000 || value < -1000) /* nodata? */ value = HUGE_VAL; else { if (inverse) z[io] -= value; else z[io] += value; } if (value != HUGE_VAL) { if (debug_count++ < 20) pj_log(defn->ctx, PJ_LOG_DEBUG_MINOR, "pj_apply_gridshift(): used %s", ct->id); break; } } if (value == HUGE_VAL) { char gridlist[3000]; pj_log(defn->ctx, PJ_LOG_DEBUG_MAJOR, "pj_apply_vgridshift(): failed to find a grid shift table for\n" " location (%.7fdW,%.7fdN)", x[io] * RAD_TO_DEG, y[io] * RAD_TO_DEG); gridlist[0] = '\0'; for (itable = 0; itable < *gridlist_count_p; itable++) { PJ_GRIDINFO *gi = tables[itable]; if (strlen(gridlist) + strlen(gi->gridname) > sizeof(gridlist) - 100) { strcat(gridlist, "..."); break; } if (itable == 0) sprintf(gridlist, " tried: %s", gi->gridname); else sprintf(gridlist + strlen(gridlist), ",%s", gi->gridname); } pj_log(defn->ctx, PJ_LOG_DEBUG_MAJOR, "%s", gridlist); pj_ctx_set_errno(defn->ctx, PJD_ERR_GRID_AREA); return PJD_ERR_GRID_AREA; } } return 0; }