Example #1
0
static PJ_COORD todeg_coord (PJ *P, PJ_DIRECTION dir, PJ_COORD a) {
    size_t i, n;
    const char *axis = "enut";
    paralist *l = pj_param_exists (P->params, "axis");
    if (l && dir==PJ_FWD)
        axis = l->param + strlen ("axis=");
    n = strlen (axis);
    for (i = 0;  i < n;  i++)
        if (strchr ("news", axis[i]))
            a.v[i] = proj_todeg (a.v[i]);
    return a;
}
Example #2
0
static PJ* read_convention(PJ* P) {

    struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *)P->opaque;

    /* In case there are rotational terms, we require an explicit convention
     * to be provided. */
    if (!Q->no_rotation) {
        const char* convention = pj_param (P->ctx, P->params, "sconvention").s;
        if( !convention ) {
            proj_log_error (P, "helmert: missing 'convention' argument");
            return pj_default_destructor (P, PJD_ERR_MISSING_ARGS);
        }
        if( strcmp(convention, "position_vector") == 0 ) {
            Q->is_position_vector = 1;
        }
        else if( strcmp(convention, "coordinate_frame") == 0 ) {
            Q->is_position_vector = 0;
        }
        else {
            proj_log_error (P, "helmert: invalid value for 'convention' argument");
            return pj_default_destructor (P, PJD_ERR_INVALID_ARG);
        }

        /* historically towgs84 in PROJ has always been using position_vector
         * convention. Accepting coordinate_frame would be confusing. */
        if (pj_param_exists (P->params, "towgs84")) {
            if( !Q->is_position_vector ) {
                proj_log_error (P, "helmert: towgs84 should only be used with "
                                "convention=position_vector");
                return pj_default_destructor (P, PJD_ERR_INVALID_ARG);
            }
        }
    }

    return P;
}
Example #3
0
static int cs2cs_emulation_setup (PJ *P) {
/**************************************************************************************
If any cs2cs style modifiers are given (axis=..., towgs84=..., ) create the 4D API
equivalent operations, so the preparation and finalization steps in the pj_inv/pj_fwd
invocators can emulate the behaviour of pj_transform and the cs2cs app.

Returns 1 on success, 0 on failure
**************************************************************************************/
    PJ *Q;
    paralist *p;
    int do_cart = 0;
    if (0==P)
        return 0;

    /* Don't recurse when calling proj_create (which calls us back) */
    if (pj_param_exists (P->params, "break_cs2cs_recursion"))
        return 1;

    /* Swap axes? */
    p = pj_param_exists (P->params, "axis");

    /* Don't axisswap if data are already in "enu" order */
    if (p && (0!=strcmp ("enu", p->param))) {
        char *def = malloc (100+strlen(P->axis));
        if (0==def)
            return 0;
        sprintf (def, "break_cs2cs_recursion     proj=axisswap  axis=%s", P->axis);
        Q = proj_create (P->ctx, def);
        free (def);
        if (0==Q)
            return 0;
        P->axisswap = skip_prep_fin(Q);
    }

    /* Geoid grid(s) given? */
    p = pj_param_exists (P->params, "geoidgrids");
    if (p  &&  strlen (p->param) > strlen ("geoidgrids=")) {
        char *gridnames = p->param + strlen ("geoidgrids=");
        char *def = malloc (100+strlen(gridnames));
        if (0==def)
            return 0;
        sprintf (def, "break_cs2cs_recursion     proj=vgridshift  grids=%s", gridnames);
        Q = proj_create (P->ctx, def);
        free (def);
        if (0==Q)
            return 0;
        P->vgridshift = skip_prep_fin(Q);
    }

    /* Datum shift grid(s) given? */
    p = pj_param_exists (P->params, "nadgrids");
    if (p  &&  strlen (p->param) > strlen ("nadgrids=")) {
        char *gridnames = p->param + strlen ("nadgrids=");
        char *def = malloc (100+strlen(gridnames));
        if (0==def)
            return 0;
        sprintf (def, "break_cs2cs_recursion     proj=hgridshift  grids=%s", gridnames);
        Q = proj_create (P->ctx, def);
        free (def);
        if (0==Q)
            return 0;
        P->hgridshift = skip_prep_fin(Q);
    }

    /* We ignore helmert if we have grid shift */
    p = P->hgridshift ? 0 : pj_param_exists (P->params, "towgs84");
    while (p) {
        char *def;
        char *s = p->param;
        double *d = P->datum_params;
        size_t n = strlen (s);

        /* We ignore null helmert shifts (common in auto-translated resource files, e.g. epsg) */
        if (0==d[0] && 0==d[1] && 0==d[2] && 0==d[3] && 0==d[4] && 0==d[5] && 0==d[6]) {
            /* If the current ellipsoid is not WGS84, then make sure the */
            /* change in ellipsoid is still done. */
            if (!(fabs(P->a_orig - 6378137.0) < 1e-8 && fabs(P->es_orig - 0.0066943799901413) < 1e-15)) {
                do_cart = 1;
            }
            break;
        }

        if (n <= 8) /* 8==strlen ("towgs84=") */
            return 0;

        def = malloc (100+n);
        if (0==def)
            return 0;
        sprintf (def, "break_cs2cs_recursion     proj=helmert exact %s transpose", s);
        Q = proj_create (P->ctx, def);
        pj_inherit_ellipsoid_def (P, Q);
        free (def);
        if (0==Q)
            return 0;
        P->helmert = skip_prep_fin (Q);

        break;
    }

    /* We also need cartesian/geographical transformations if we are working in */
    /* geocentric/cartesian space or we need to do a Helmert transform.         */
    if (P->is_geocent || P->helmert || do_cart) {
        char def[150];
        sprintf (def, "break_cs2cs_recursion     proj=cart   a=%40.20g  es=%40.20g", P->a_orig, P->es_orig);
        Q = proj_create (P->ctx, def);
        if (0==Q)
            return 0;
        P->cart = skip_prep_fin (Q);

        sprintf (def, "break_cs2cs_recursion     proj=cart  ellps=WGS84");
        Q = proj_create (P->ctx, def);
        if (0==Q)
            return 0;
        P->cart_wgs84 = skip_prep_fin (Q);
    }

    return 1;
}
Example #4
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;
}
Example #5
0
static paralist *append_defaults_to_paralist (PJ_CONTEXT *ctx, paralist *start, char *key) {
    paralist *defaults, *last = 0;
    char keystring[ID_TAG_MAX + 20];
    paralist *next, *proj;
    int err;

    if (0==start)
        return 0;

    if (strlen(key) > ID_TAG_MAX)
        return 0;

    /* Set defaults, unless inhibited (either explicitly through a "no_defs" token */
    /* or implicitly, because we are initializing a pipeline) */
    if (pj_param_exists (start, "no_defs"))
        return start;
    proj = pj_param_exists (start, "proj");
    if (0==proj)
        return start;
    if (strlen (proj->param) < 6)
        return start;
    if (0==strcmp ("pipeline", proj->param + 5))
        return start;

    err = pj_ctx_get_errno (ctx);
    pj_ctx_set_errno (ctx, 0);

    /* Locate end of start-list */
    for (last = start;  last->next;  last = last->next);

    strcpy (keystring, "proj_def.dat:");
    strcat (keystring, key);
    defaults = get_init (ctx, keystring);

    /* Defaults are optional - so we don't care if we cannot open the file */
    pj_ctx_set_errno (ctx, err);

    if (!defaults)
        return last;

    /* Loop over all default items */
    for (next = defaults;  next;  next = next->next) {

        /* Don't override existing parameter value of same name */
        if (pj_param_exists (start, next->param))
            continue;

        /* Don't default ellipse if datum, ellps or any ellipsoid information is set */
        if (0==strncmp(next->param,"ellps=", 6)) {
            if  (pj_param_exists (start, "datum"))  continue;
            if  (pj_param_exists (start, "ellps"))  continue;
            if  (pj_param_exists (start, "a"))      continue;
            if  (pj_param_exists (start, "b"))      continue;
            if  (pj_param_exists (start, "rf"))     continue;
            if  (pj_param_exists (start, "f"))      continue;
            if  (pj_param_exists (start, "e"))      continue;
            if  (pj_param_exists (start, "es"))     continue;
        }

        /* If we're here, it's OK to append the current default item */
        last = last->next = pj_mkparam(next->param);
    }
    last->next = 0;

    pj_dealloc_params (ctx, defaults, 0);
    return last;
}