PJ_DEF(void) pj_log_6(const char *obj, const char *format, ...) { va_list arg; va_start(arg, format); pj_log(obj, 6, format, arg); va_end(arg); }
static void ffmpeg_log_cb(void* ptr, int level, const char* fmt, va_list vl) { const char *LOG_SENDER = "ffmpeg"; enum { LOG_LEVEL = 5 }; char buf[100]; int bufsize = sizeof(buf), len; pj_str_t fmt_st; /* Custom callback needs to filter log level by itself */ if (level > av_log_get_level()) return; /* Add original ffmpeg sender to log format */ if (ptr) { AVClass* avc = *(AVClass**)ptr; len = pj_ansi_snprintf(buf, bufsize, "%s: ", avc->item_name(ptr)); bufsize -= len; } /* Copy original log format */ len = pj_ansi_strlen(fmt); if (len > bufsize-1) len = bufsize-1; pj_memcpy(buf+sizeof(buf)-bufsize, fmt, len); bufsize -= len; /* Trim log format */ pj_strset(&fmt_st, buf, sizeof(buf)-bufsize); pj_strrtrim(&fmt_st); buf[fmt_st.slen] = '\0'; pj_log(LOG_SENDER, LOG_LEVEL, buf, vl); }
static void invoke_log(const char *sender, int level, const char *format, ...) { va_list arg; va_start(arg, format); pj_log(sender, level, format, arg); va_end(arg); }
static paralist *get_init(PJ_CONTEXT *ctx, char *key) { /************************************************************************* Expand key from buffer or (if not in buffer) from init file *************************************************************************/ char *xkey, *definition; paralist *init_items = 0; /* support "init=file:section", "+init=file:section", and "file:section" format */ xkey = strstr (key, "init="); if (0==xkey) xkey = key; else xkey += 5; pj_log (ctx, PJ_LOG_TRACE, "get_init: searching cache for key: [%s]", xkey); /* Is file/key pair already in cache? */ init_items = pj_search_initcache (xkey); if (init_items) return init_items; /* If not, we must read it from file */ pj_log (ctx, PJ_LOG_TRACE, "get_init: searching on in init files for [%s]", xkey); definition = get_init_string (ctx, xkey); if (0==definition) return 0; init_items = string_to_paralist (ctx, definition); if (init_items) pj_log (ctx, PJ_LOG_TRACE, "get_init: got [%s], paralist[0,1]: [%s,%s]", definition, init_items->param, init_items->next ? init_items->next->param : "(empty)"); pj_dealloc (definition); if (0==init_items) return 0; /* We found it in file - now insert into the cache, before returning */ pj_insert_initcache (xkey, init_items); return init_items; }
void srtp_err_report(srtp_err_reporting_level_t priority, const char *format, ...) { va_list args; #if PJ_LOG_MAX_LEVEL >= 1 if (priority <= err_level) { va_start(args, format); pj_log("libsrtp", priority, format, args); va_end(args); } #endif }
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_gc_readentry(projCtx ctx, PAFile fid, PJ_GridCatalogEntry *entry) { #define MAX_TOKENS 30 char *tokens[MAX_TOKENS]; int token_count, i; int error = 0; memset( entry, 0, sizeof(PJ_GridCatalogEntry) ); token_count = pj_gc_read_csv_line( ctx, fid, tokens, MAX_TOKENS ); if( token_count < 5 ) { error = 1; /* TODO: need real error codes */ if( token_count != 0 ) pj_log( ctx, PJ_LOG_ERROR, "Short line in grid catalog." ); } else { memset( entry, 0, sizeof(PJ_GridCatalogEntry)); entry->definition = strdup( tokens[0] ); entry->region.ll_long = dmstor_ctx( ctx, tokens[1], NULL ); entry->region.ll_lat = dmstor_ctx( ctx, tokens[2], NULL ); entry->region.ur_long = dmstor_ctx( ctx, tokens[3], NULL ); entry->region.ur_lat = dmstor_ctx( ctx, tokens[4], NULL ); if( token_count > 5 ) entry->priority = atoi( tokens[5] ); /* defaults to zero */ if( token_count > 6 ) entry->date = pj_gc_parsedate( ctx, tokens[6] ); } for( i = 0; i < token_count; i++ ) free( tokens[i] ); return error; }
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; } }
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; }
static char *get_init_string (PJ_CONTEXT *ctx, char *name) { /*************************************************************************************** Read a section of an init file. Return its contents as a plain character string. It is the duty of the caller to free the memory allocated for the string. ***************************************************************************************/ #define MAX_LINE_LENGTH 1000 size_t current_buffer_size = 5 * (MAX_LINE_LENGTH + 1); char *fname, *section, *key; char *buffer = 0; char *line = 0; PAFile fid; size_t n; line = pj_malloc (MAX_LINE_LENGTH + 1); if (0==line) return 0; fname = pj_malloc (MAX_PATH_FILENAME+ID_TAG_MAX+3); if (0==fname) { pj_dealloc (line); return 0; } /* Support "init=file:section", "+init=file:section", and "file:section" format */ key = strstr (name, "init="); if (0==key) key = name; else key += 5; if (MAX_PATH_FILENAME + ID_TAG_MAX + 2 < strlen (key)) { pj_dealloc (fname); pj_dealloc (line); return 0; } memmove (fname, key, strlen (key) + 1); /* Locate the name of the section we search for */ section = strrchr(fname, ':'); if (0==section) { proj_context_errno_set (ctx, PJD_ERR_NO_COLON_IN_INIT_STRING); pj_dealloc (fname); pj_dealloc (line); return 0; } *section = 0; section++; n = strlen (section); pj_log (ctx, PJ_LOG_TRACE, "get_init_string: searching for section [%s] in init file [%s]", section, fname); fid = pj_open_lib (ctx, fname, "rt"); if (0==fid) { pj_dealloc (fname); pj_dealloc (line); proj_context_errno_set (ctx, PJD_ERR_NO_OPTION_IN_INIT_FILE); return 0; } /* Search for section in init file */ for (;;) { /* End of file? */ if (0==pj_ctx_fgets (ctx, line, MAX_LINE_LENGTH, fid)) { pj_dealloc (buffer); pj_dealloc (fname); pj_dealloc (line); pj_ctx_fclose (ctx, fid); proj_context_errno_set (ctx, PJD_ERR_NO_OPTION_IN_INIT_FILE); return 0; } /* At start of right section? */ pj_chomp (line); if ('<'!=line[0]) continue; if (strlen (line) < n + 2) continue; if (line[n + 1] != '>') continue; if (0==strncmp (line + 1, section, n)) break; } /* We're at the first line of the right section - copy line to buffer */ buffer = pj_malloc (current_buffer_size); if (0==buffer) { pj_dealloc (fname); pj_dealloc (line); pj_ctx_fclose (ctx, fid); return 0; } /* Skip the "<section>" indicator, and copy the rest of the line over */ strcpy (buffer, line + strlen (section) + 2); /* Copy the remaining lines of the section to buffer */ for (;;) { char *end_i_cator; size_t next_length, buffer_length; /* Did the section end somewhere in the most recently read line? */ end_i_cator = strchr (buffer, '<'); if (end_i_cator) { *end_i_cator = 0; break; } /* End of file? - done! */ if (0==pj_ctx_fgets (ctx, line, MAX_LINE_LENGTH, fid)) break; /* Otherwise, handle the line. It MAY be the start of the next section, */ /* but that will be handled at the start of next trip through the loop */ buffer_length = strlen (buffer); pj_chomp (line); /* Remove '#' style comments */ next_length = strlen (line) + buffer_length + 2; if (next_length > current_buffer_size) { char *b = pj_malloc (2 * current_buffer_size); if (0==b) { pj_dealloc (buffer); buffer = 0; break; } strcpy (b, buffer); current_buffer_size *= 2; pj_dealloc (buffer); buffer = b; } buffer[buffer_length] = ' '; strcpy (buffer + buffer_length + 1, line); } pj_ctx_fclose (ctx, fid); pj_dealloc (fname); pj_dealloc (line); if (0==buffer) return 0; pj_shrink (buffer); pj_log (ctx, PJ_LOG_TRACE, "key=%s, value: [%s]", key, buffer); return buffer; }
static int pj_gridinfo_init_ntv2( projCtx ctx, FILE *fid, PJ_GRIDINFO *gilist ) { unsigned char header[11*16]; int num_subfiles, subfile; 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 pj_gridinfo_init_ntv2()" ); pj_ctx_set_errno( ctx, -38 ); return 0; } /* -------------------------------------------------------------------- */ /* Read the overview header. */ /* -------------------------------------------------------------------- */ if( fread( header, sizeof(header), 1, fid ) != 1 ) { pj_ctx_set_errno( ctx, -38 ); return 0; } /* -------------------------------------------------------------------- */ /* Byte swap interesting fields if needed. */ /* -------------------------------------------------------------------- */ if( !IS_LSB ) { 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( fread( header, sizeof(header), 1, fid ) != 1 ) { pj_ctx_set_errno( ctx, -38 ); return 0; } if( strncmp((const char *) header,"SUB_NAME",8) != 0 ) { pj_ctx_set_errno( ctx, -38 ); return 0; } /* -------------------------------------------------------------------- */ /* Byte swap interesting fields if needed. */ /* -------------------------------------------------------------------- */ if( !IS_LSB ) { 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)); strncpy( ct->id, (const char *) header + 8, 8 ); ct->id[8] = '\0'; ct->ll.lam = - *((double *) (header+7*16+8)); /* W_LONG */ ct->ll.phi = *((double *) (header+4*16+8)); /* S_LAT */ ur.lam = - *((double *) (header+6*16+8)); /* E_LONG */ ur.phi = *((double *) (header+5*16+8)); /* N_LAT */ ct->del.lam = *((double *) (header+9*16+8)); ct->del.phi = *((double *) (header+8*16+8)); 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, "NTv2 %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)\n", 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)\n", gs_count, ct->lim.lam, ct->lim.phi, ct->lim.lam * ct->lim.phi ); pj_ctx_set_errno( ctx, -38 ); 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_malloc(sizeof(PJ_GRIDINFO)); memset( gi, 0, sizeof(PJ_GRIDINFO) ); gi->gridname = strdup( gilist->gridname ); gi->filename = strdup( gilist->filename ); gi->next = NULL; } gi->ct = ct; gi->format = "ntv2"; gi->grid_offset = ftell( 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 = gilist; while( gp != NULL && strncmp(gp->ct->id,(const char*)header+24,8) != 0 ) gp = gp->next; if( gp == NULL ) { pj_log( ctx, PJ_LOG_ERROR, "pj_gridinfo_init_ntv2(): " "failed to find parent %8.8s for %s.\n", (const char *) header+24, gi->ct->id ); for( lnk = gp; 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. */ /* -------------------------------------------------------------------- */ fseek( fid, gs_count * 16, SEEK_CUR ); } return 1; }
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; }
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_GRIDINFO *pj_gridinfo_init( projCtx ctx, const char *gridname ) { char fname[MAX_PATH_FILENAME+1]; PJ_GRIDINFO *gilist; FILE *fp; char header[160]; 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_malloc(sizeof(PJ_GRIDINFO)); memset( gilist, 0, sizeof(PJ_GRIDINFO) ); gilist->gridname = strdup( gridname ); 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 = strdup(fname); /* -------------------------------------------------------------------- */ /* Load a header, to determine the file type. */ /* -------------------------------------------------------------------- */ if( fread( header, sizeof(header), 1, fp ) != 1 ) { fclose( fp ); pj_ctx_set_errno( ctx, -38 ); return gilist; } fseek( fp, SEEK_SET, 0 ); /* -------------------------------------------------------------------- */ /* Determine file type. */ /* -------------------------------------------------------------------- */ if( 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( 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( strncmp(header+0,"CTABLE V2",9) == 0 ) { struct CTABLE *ct = nad_ctable2_init( ctx, fp ); gilist->format = "ctable2"; gilist->ct = ct; pj_log( ctx, PJ_LOG_DEBUG_MAJOR, "Ctable2 %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)\n", 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 ); gilist->format = "ctable"; gilist->ct = ct; pj_log( ctx, PJ_LOG_DEBUG_MAJOR, "Ctable %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)\n", 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 ); } fclose(fp); return gilist; }
int pj_apply_gridshift_3( projCtx ctx, PJ_GRIDINFO **tables, int grid_count, int inverse, long point_count, int point_offset, double *x, double *y, double *z ) { int i; static int debug_count = 0; if( tables == NULL || grid_count == 0 ) { pj_ctx_set_errno( ctx, -38); return -38; } ctx->last_errno = 0; for( i = 0; i < point_count; i++ ) { long io = i * point_offset; LP input, output; int itable; input.phi = y[io]; input.lam = x[io]; output.phi = HUGE_VAL; output.lam = HUGE_VAL; /* keep trying till we find a table that works */ for( itable = 0; itable < grid_count; itable++ ) { PJ_GRIDINFO *gi = tables[itable]; struct CTABLE *ct = gi->ct; double epsilon = (fabs(ct->del.phi)+fabs(ct->del.lam))/10000.0; /* skip tables that don't match our point at all. */ if( ct->ll.phi - epsilon > input.phi || ct->ll.lam - epsilon > input.lam || (ct->ll.phi + (ct->lim.phi-1) * ct->del.phi + epsilon < input.phi) || (ct->ll.lam + (ct->lim.lam-1) * ct->del.lam + epsilon < 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; double epsilon = (fabs(ct1->del.phi)+fabs(ct1->del.lam))/10000.0; if( ct1->ll.phi - epsilon > input.phi || ct1->ll.lam - epsilon > input.lam || (ct1->ll.phi+(ct1->lim.phi-1)*ct1->del.phi + epsilon < input.phi) || (ct1->ll.lam+(ct1->lim.lam-1)*ct1->del.lam + epsilon < 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( ctx, gi ) ) { pj_ctx_set_errno( ctx, -38 ); return -38; } output = nad_cvt( input, inverse, ct ); if( output.lam != HUGE_VAL ) { if( debug_count++ < 20 ) pj_log( ctx, PJ_LOG_DEBUG_MINOR, "pj_apply_gridshift(): used %s", ct->id ); break; } } if( output.lam == HUGE_VAL ) { if( ctx->debug_level >= PJ_LOG_DEBUG_MAJOR ) { pj_log( 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 ); for( itable = 0; itable < grid_count; itable++ ) { PJ_GRIDINFO *gi = tables[itable]; if( itable == 0 ) pj_log( ctx, PJ_LOG_DEBUG_MAJOR, " tried: %s", gi->gridname ); else pj_log( ctx, PJ_LOG_DEBUG_MAJOR, ",%s", gi->gridname ); } } /* * We don't actually have any machinery currently to set the * following macro, so this is mostly kept here to make it clear * how we ought to operate if we wanted to make it super clear * that an error has occured when points are outside our available * datum shift areas. But if this is on, we will find that "low * value" points on the fringes of some datasets will completely * fail causing lots of problems when it is more or less ok to * just not apply a datum shift. So rather than deal with * that we just fallback to no shift. (see also bug #45). */ #ifdef ERR_GRID_AREA_TRANSIENT_SEVERE y[io] = HUGE_VAL; x[io] = HUGE_VAL; #else /* leave x/y unshifted. */ #endif } else { y[io] = output.phi; x[io] = output.lam; } } return 0; }
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; }
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; }
PJ * pj_init_ctx(projCtx ctx, int argc, char **argv) { char *s, *name; PJ_CONSTRUCTOR proj; paralist *curr, *init, *start; int i; int err; PJ *PIN = 0; int n_pipelines = 0; int n_inits = 0; if (0==ctx) ctx = pj_get_default_ctx (); ctx->last_errno = 0; if (argc <= 0) { pj_ctx_set_errno (ctx, PJD_ERR_NO_ARGS); return 0; } /* count occurrences of pipelines and inits */ for (i = 0; i < argc; ++i) { if (!strcmp (argv[i], "+proj=pipeline") || !strcmp(argv[i], "proj=pipeline") ) n_pipelines++; if (!strncmp (argv[i], "+init=", 6) || !strncmp(argv[i], "init=", 5)) n_inits++; } /* can't have nested pipelines directly */ if (n_pipelines > 1) { pj_ctx_set_errno (ctx, PJD_ERR_MALFORMED_PIPELINE); return 0; } /* don't allow more than one +init in non-pipeline operations */ if (n_pipelines == 0 && n_inits > 1) { pj_ctx_set_errno (ctx, PJD_ERR_TOO_MANY_INITS); return 0; } /* put arguments into internal linked list */ start = curr = pj_mkparam(argv[0]); if (!curr) return pj_dealloc_params (ctx, start, ENOMEM); for (i = 1; i < argc; ++i) { curr->next = pj_mkparam(argv[i]); if (!curr->next) return pj_dealloc_params (ctx, start, ENOMEM); curr = curr->next; } /* Only expand '+init's in non-pipeline operations. '+init's in pipelines are */ /* expanded in the individual pipeline steps during pipeline initialization. */ /* Potentially this leads to many nested pipelines, which shouldn't be a */ /* problem when '+init's are expanded as late as possible. */ init = pj_param_exists (start, "init"); if (init && n_pipelines == 0) { init = pj_expand_init (ctx, init); if (!init) return pj_dealloc_params (ctx, start, PJD_ERR_NO_ARGS); } if (ctx->last_errno) return pj_dealloc_params (ctx, start, ctx->last_errno); /* Find projection selection */ curr = pj_param_exists (start, "proj"); if (0==curr) return pj_dealloc_params (ctx, start, PJD_ERR_PROJ_NOT_NAMED); name = curr->param; if (strlen (name) < 6) return pj_dealloc_params (ctx, start, PJD_ERR_PROJ_NOT_NAMED); name += 5; proj = locate_constructor (name); if (0==proj) return pj_dealloc_params (ctx, start, PJD_ERR_UNKNOWN_PROJECTION_ID); /* Append general and projection specific defaults to the definition list */ append_defaults_to_paralist (ctx, start, "general"); append_defaults_to_paralist (ctx, start, name); /* Allocate projection structure */ PIN = proj(0); if (0==PIN) return pj_dealloc_params (ctx, start, ENOMEM); PIN->ctx = ctx; PIN->params = start; PIN->is_latlong = 0; PIN->is_geocent = 0; PIN->is_long_wrap_set = 0; PIN->long_wrap_center = 0.0; strcpy( PIN->axis, "enu" ); PIN->gridlist = NULL; PIN->gridlist_count = 0; PIN->vgridlist_geoid = NULL; PIN->vgridlist_geoid_count = 0; /* Set datum parameters. Similarly to +init parameters we want to expand */ /* +datum parameters as late as possible when dealing with pipelines. */ /* otherwise only the first occurrence of +datum will be expanded and that */ if (n_pipelines == 0) { if (pj_datum_set(ctx, start, PIN)) return pj_default_destructor (PIN, proj_errno(PIN)); } err = pj_ellipsoid (PIN); if (err) { /* Didn't get an ellps, but doesn't need one: Get a free WGS84 */ if (PIN->need_ellps) { pj_log (ctx, PJ_LOG_DEBUG_MINOR, "pj_init_ctx: Must specify ellipsoid or sphere"); return pj_default_destructor (PIN, proj_errno(PIN)); } else { if (PJD_ERR_MAJOR_AXIS_NOT_GIVEN==proj_errno (PIN)) proj_errno_reset (PIN); PIN->f = 1.0/298.257223563; PIN->a_orig = PIN->a = 6378137.0; PIN->es_orig = PIN->es = PIN->f*(2-PIN->f); } } PIN->a_orig = PIN->a; PIN->es_orig = PIN->es; if (pj_calc_ellipsoid_params (PIN, PIN->a, PIN->es)) return pj_default_destructor (PIN, PJD_ERR_ECCENTRICITY_IS_ONE); /* Now that we have ellipse information check for WGS84 datum */ if( PIN->datum_type == PJD_3PARAM && PIN->datum_params[0] == 0.0 && PIN->datum_params[1] == 0.0 && PIN->datum_params[2] == 0.0 && PIN->a == 6378137.0 && ABS(PIN->es - 0.006694379990) < 0.000000000050 )/*WGS84/GRS80*/ { PIN->datum_type = PJD_WGS84; } /* Set PIN->geoc coordinate system */ PIN->geoc = (PIN->es != 0.0 && pj_param(ctx, start, "bgeoc").i); /* Over-ranging flag */ PIN->over = pj_param(ctx, start, "bover").i; /* Vertical datum geoid grids */ PIN->has_geoid_vgrids = pj_param(ctx, start, "tgeoidgrids").i; if( PIN->has_geoid_vgrids ) /* we need to mark it as used. */ pj_param(ctx, start, "sgeoidgrids"); /* Longitude center for wrapping */ PIN->is_long_wrap_set = pj_param(ctx, start, "tlon_wrap").i; if (PIN->is_long_wrap_set) { PIN->long_wrap_center = pj_param(ctx, start, "rlon_wrap").f; /* Don't accept excessive values otherwise we might perform badly */ /* when correcting longitudes around it */ /* The test is written this way to error on long_wrap_center "=" NaN */ if( !(fabs(PIN->long_wrap_center) < 10 * M_TWOPI) ) return pj_default_destructor (PIN, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); } /* Axis orientation */ if( (pj_param(ctx, start,"saxis").s) != NULL ) { const char *axis_legal = "ewnsud"; const char *axis_arg = pj_param(ctx, start,"saxis").s; if( strlen(axis_arg) != 3 ) return pj_default_destructor (PIN, PJD_ERR_AXIS); if( strchr( axis_legal, axis_arg[0] ) == NULL || strchr( axis_legal, axis_arg[1] ) == NULL || strchr( axis_legal, axis_arg[2] ) == NULL) return pj_default_destructor (PIN, PJD_ERR_AXIS); /* TODO: it would be nice to validate we don't have on axis repeated */ strcpy( PIN->axis, axis_arg ); } /* Central meridian */ PIN->lam0=pj_param(ctx, start, "rlon_0").f; /* Central latitude */ PIN->phi0 = pj_param(ctx, start, "rlat_0").f; /* False easting and northing */ PIN->x0 = pj_param(ctx, start, "dx_0").f; PIN->y0 = pj_param(ctx, start, "dy_0").f; PIN->z0 = pj_param(ctx, start, "dz_0").f; PIN->t0 = pj_param(ctx, start, "dt_0").f; /* General scaling factor */ if (pj_param(ctx, start, "tk_0").i) PIN->k0 = pj_param(ctx, start, "dk_0").f; else if (pj_param(ctx, start, "tk").i) PIN->k0 = pj_param(ctx, start, "dk").f; else PIN->k0 = 1.; if (PIN->k0 <= 0.) return pj_default_destructor (PIN, PJD_ERR_K_LESS_THAN_ZERO); /* Set units */ s = 0; if ((name = pj_param(ctx, start, "sunits").s) != NULL) { for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i) ; if (!s) return pj_default_destructor (PIN, PJD_ERR_UNKNOWN_UNIT_ID); s = pj_units[i].to_meter; } if (s || (s = pj_param(ctx, start, "sto_meter").s)) { double factor; int ratio = 0; /* ratio number? */ if (strlen (s) > 1 && s[0] == '1' && s[1]=='/') { ratio = 1; s += 2; } factor = pj_strtod(s, &s); if ((factor <= 0.0) || (1/factor==0)) return pj_default_destructor (PIN, PJD_ERR_UNIT_FACTOR_LESS_THAN_0); PIN->to_meter = ratio? 1 / factor: factor; PIN->fr_meter = 1 / PIN->to_meter; } else PIN->to_meter = PIN->fr_meter = 1.; /* Set vertical units */ s = 0; if ((name = pj_param(ctx, start, "svunits").s) != NULL) { for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i) ; if (!s) return pj_default_destructor (PIN, PJD_ERR_UNKNOWN_UNIT_ID); s = pj_units[i].to_meter; } if (s || (s = pj_param(ctx, start, "svto_meter").s)) { PIN->vto_meter = pj_strtod(s, &s); if (*s == '/') /* ratio number */ PIN->vto_meter /= pj_strtod(++s, 0); if (PIN->vto_meter <= 0.0) return pj_default_destructor (PIN, PJD_ERR_UNIT_FACTOR_LESS_THAN_0); PIN->vfr_meter = 1. / PIN->vto_meter; } else { PIN->vto_meter = PIN->to_meter; PIN->vfr_meter = PIN->fr_meter; } /* Prime meridian */ s = 0; if ((name = pj_param(ctx, start, "spm").s) != NULL) { const char *value = NULL; char *next_str = NULL; for (i = 0; pj_prime_meridians[i].id != NULL; ++i ) { if( strcmp(name,pj_prime_meridians[i].id) == 0 ) { value = pj_prime_meridians[i].defn; break; } } if( value == NULL && (dmstor_ctx(ctx,name,&next_str) != 0.0 || *name == '0') && *next_str == '\0' ) value = name; if (!value) return pj_default_destructor (PIN, PJD_ERR_UNKNOWN_PRIME_MERIDIAN); PIN->from_greenwich = dmstor_ctx(ctx,value,NULL); } else PIN->from_greenwich = 0.0; /* Private object for the geodesic functions */ PIN->geod = pj_calloc (1, sizeof (struct geod_geodesic)); if (0==PIN->geod) return pj_default_destructor (PIN, ENOMEM); geod_init(PIN->geod, PIN->a, (1 - sqrt (1 - PIN->es))); /* Projection specific initialization */ err = proj_errno_reset (PIN); PIN = proj(PIN); if (proj_errno (PIN)) { pj_free(PIN); return 0; } proj_errno_restore (PIN, err); return PIN; }