示例#1
0
文件: path.cpp 项目: goalizc/takisy
rectf path::bbox(void) const
{
    if (size() == 0)
        return rectf(0, 0, 0, 0);
    else
    {
        vertex_type vertex = fetch_vertex(0);
        rectf bbox(vertex.x, vertex.y, vertex.x, vertex.y);

        for (unsigned int i = 1; i < size(); ++i)
        {
            vertex = fetch_vertex(i);

            if (bbox.left   > vertex.x) bbox.left   = vertex.x;
            else
            if (bbox.right  < vertex.x) bbox.right  = vertex.x;

            if (bbox.top    > vertex.y) bbox.top    = vertex.y;
            else
            if (bbox.bottom < vertex.y) bbox.bottom = vertex.y;
        }

        return bbox;
    }
}
示例#2
0
文件: path.cpp 项目: goalizc/takisy
bool path::pnpoly(vertex_type::axis_type x, vertex_type::axis_type y) const
{
    bool c = false;

    for (unsigned int i = 0, j = size() - 1; i < size(); j = i++)
    {
        vertex_type vi = fetch_vertex(i);
        vertex_type vj = fetch_vertex(j);

        if (((vi.y > y) != (vj.y > y))
            && (x < vi.x - (vi.y - y) * (vi.x - vj.x) / (vi.y - vj.y)))
            c = !c;
    }

    return c;
}
示例#3
0
static int compute_alpha_shape(char* sql, vertex_t **res, int *res_count)
{

    int SPIcode;
    void *SPIplan;
    Portal SPIportal;
    bool moredata = TRUE;
    int ntuples;
    vertex_t *vertices = NULL;
    int total_tuples = 0;
    vertex_columns_t vertex_columns = {.id= -1, .x= -1, .y= -1};
    char *err_msg;
    int ret = -1;

    DBG("start alpha_shape\n");

    SPIcode = SPI_connect();
    if (SPIcode  != SPI_OK_CONNECT)
    {
        elog(ERROR, "alpha_shape: couldn't open a connection to SPI");
        return -1;
    }

    SPIplan = SPI_prepare(sql, 0, NULL);
    if (SPIplan  == NULL)
    {
        elog(ERROR, "alpha_shape: couldn't create query plan via SPI");
        return -1;
    }

    if ((SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL)
    {
        elog(ERROR, "alpha_shape: SPI_cursor_open('%s') returns NULL", sql);
        return -1;
    }

    while (moredata == TRUE)
    {
        SPI_cursor_fetch(SPIportal, TRUE, TUPLIMIT);

        if (vertex_columns.id == -1)
        {
            if (fetch_vertices_columns(SPI_tuptable, &vertex_columns) == -1)
                return finish(SPIcode, ret);
        }

        ntuples = SPI_processed;
        total_tuples += ntuples;
        if (!vertices)
            vertices = palloc(total_tuples * sizeof(vertex_t));
        else
            vertices = repalloc(vertices, total_tuples * sizeof(vertex_t));

        if (vertices == NULL)
        {
            elog(ERROR, "Out of memory");
            return finish(SPIcode, ret);
        }

        if (ntuples > 0)
        {
            int t;
            SPITupleTable *tuptable = SPI_tuptable;
            TupleDesc tupdesc = SPI_tuptable->tupdesc;

            for (t = 0; t < ntuples; t++)
            {
                HeapTuple tuple = tuptable->vals[t];
                fetch_vertex(&tuple, &tupdesc, &vertex_columns,
                             &vertices[total_tuples - ntuples + t]);
            }
            SPI_freetuptable(tuptable);
        }
        else
        {
            moredata = FALSE;
        }
    }


    // if (total_tuples < 2) //this was the buggy code of the pgrouting project.
    // TODO: report this as a bug to the pgrouting project
    // the CGAL alpha-shape function crashes if called with less than three points!!!

    if (total_tuples == 0) {
        elog(ERROR, "Distance is too short. no vertex for alpha shape calculation. alpha shape calculation needs at least 3 vertices.");
    }
    if (total_tuples == 1) {
        elog(ERROR, "Distance is too short. only 1 vertex for alpha shape calculation. alpha shape calculation needs at least 3 vertices.");
    }
    if (total_tuples == 2) {
        elog(ERROR, "Distance is too short. only 2 vertices for alpha shape calculation. alpha shape calculation needs at least 3 vertices.");
    }
    if (total_tuples < 3)
    {
        // elog(ERROR, "Distance is too short ....");
        return finish(SPIcode, ret);
    }

    DBG("Calling CGAL alpha-shape\n");

    profstop("extract", prof_extract);
    profstart(prof_alpha);

    ret = alpha_shape(vertices, total_tuples, res, res_count, &err_msg);

    profstop("alpha", prof_alpha);
    profstart(prof_store);

    if (ret < 0)
    {
        //elog(ERROR, "Error computing shape: %s", err_msg);
        ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), errmsg("Error computing shape: %s", err_msg)));
    }

    return finish(SPIcode, ret);
}

PG_FUNCTION_INFO_V1(alphashape);

Datum alphashape(PG_FUNCTION_ARGS)
{
    FuncCallContext      *funcctx;
    int                  call_cntr;
    int                  max_calls;
    TupleDesc            tuple_desc;
    vertex_t     *res = 0;

    /* stuff done only on the first call of the function */
    if (SRF_IS_FIRSTCALL())
    {
        MemoryContext   oldcontext;
        int res_count;
        int ret;

        // XXX profiling messages are not thread safe
        profstart(prof_total);
        profstart(prof_extract);

        /* create a function context for cross-call persistence */
        funcctx = SRF_FIRSTCALL_INIT();

        /* switch to memory context appropriate for multiple function calls */
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        ret = compute_alpha_shape(text2char(PG_GETARG_TEXT_P(0)),
                                  &res, &res_count);

        /* total number of tuples to be returned */
        DBG("Conting tuples number\n");
        funcctx->max_calls = res_count;
        funcctx->user_fctx = res;

        DBG("Total count %i", res_count);

        if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                            "that cannot accept type record")));

        funcctx->tuple_desc = BlessTupleDesc(tuple_desc);

        MemoryContextSwitchTo(oldcontext);
    }

    /* stuff done on every call of the function */
    DBG("Strange stuff doing\n");
    funcctx = SRF_PERCALL_SETUP();

    call_cntr = funcctx->call_cntr;
    max_calls = funcctx->max_calls;
    tuple_desc = funcctx->tuple_desc;
    res = (vertex_t*) funcctx->user_fctx;

    DBG("Trying to allocate some memory\n");

    if (call_cntr < max_calls)    /* do when there is more left to send */
    {
        HeapTuple    tuple;
        Datum        result;
        Datum *values;
        char* nulls;

        /* This will work for some compilers. If it crashes with segfault, try to change the following block with this one

        values = palloc(3 * sizeof(Datum));
        nulls = palloc(3 * sizeof(char));

        values[0] = call_cntr;
        nulls[0] = ' ';
        values[1] = Float8GetDatum(res[call_cntr].x);
        nulls[1] = ' ';
        values[2] = Float8GetDatum(res[call_cntr].y);
        nulls[2] = ' ';
        */

        values = palloc(2 * sizeof(Datum));
        nulls = palloc(2 * sizeof(char));

        values[0] = Float8GetDatum(res[call_cntr].x);
        nulls[0] = ' ';
        values[1] = Float8GetDatum(res[call_cntr].y);
        nulls[1] = ' ';

        DBG("Heap making\n");

        tuple = heap_formtuple(tuple_desc, values, nulls);

        DBG("Datum making\n");

        /* make the tuple into a datum */
        result = HeapTupleGetDatum(tuple);

        DBG("Trying to free some memory\n");

        /* clean up (this is not really necessary) */
        pfree(values);
        pfree(nulls);

        SRF_RETURN_NEXT(funcctx, result);
    }
    else    /* do when there is no more left */
    {
        if (res) free(res);
        profstop("store", prof_store);
        profstop("total", prof_total);
#ifdef PROFILE
        elog(NOTICE, "_________");
#endif
        SRF_RETURN_DONE(funcctx);
    }
}