Changeset 4847

Show
Ignore:
Timestamp:
11/17/09 12:03:50 (2 years ago)
Author:
pramsey
Message:

Implement ST_CollectionExtract() to pull specific homogeneous collections out of heterogeneous collections. Regressions and documentation included. (#218)

Location:
trunk
Files:
10 modified

Legend:

Unmodified
Added
Removed
  • trunk/doc/reference_editor.xml

    r4817 r4847  
    606606        </refentry> 
    607607 
     608        <refentry id="ST_CollectionExtract"> 
     609                <refnamediv> 
     610                        <refname>ST_CollectionExtract</refname> 
     611 
     612                        <refpurpose>Given a GEOMETRYCOLLECTION, returns the a MULTI* geometry consisting only the specified type. Sub-geometries that are not 
     613                            the specified type are ignored.</refpurpose> 
     614                </refnamediv> 
     615 
     616                <refsynopsisdiv> 
     617                        <funcsynopsis> 
     618                          <funcprototype> 
     619                                <funcdef>geometry <function>ST_CollectionExtract</function></funcdef> 
     620                                <paramdef><type>geometry </type> <parameter>collection</parameter></paramdef> 
     621                                <paramdef><type>integer </type> <parameter>type</parameter></paramdef> 
     622                          </funcprototype> 
     623                        </funcsynopsis> 
     624                </refsynopsisdiv> 
     625 
     626                <refsection> 
     627                        <title>Description</title> 
     628 
     629                        <para>Given a GEOMETRYCOLLECTION, returns the a MULTI* geometry consisting only the specified type. Sub-geometries that are not 
     630                            the specified type are ignored. If there are no sub-geometries of the right type, an EMPTY collection will be returned. Only 
     631                            points, lines and polygons are supported.</para> 
     632 
     633                </refsection> 
     634 
     635                <refsection> 
     636                        <title>Examples</title> 
     637 
     638                        <programlisting>SELECT ST_AsText(ST_CollectionExtract(ST_GeomFromText('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0)))'),1)); 
     639                        st_astext 
     640                        --------------- 
     641                        MULTIPOINT(0 0) 
     642                        (1 row) 
     643                        </programlisting> 
     644                </refsection> 
     645                <refsection> 
     646                        <title>See Also</title> 
     647                        <para><xref linkend="ST_Multi" /></para> 
     648                </refsection> 
     649        </refentry> 
     650         
    608651        <refentry id="ST_Multi"> 
    609652                <refnamediv> 
  • trunk/liblwgeom/cunit/cu_libgeom.c

    r4654 r4847  
    3838            (NULL == CU_add_test(pSuite, "test_lwgeom_count_vertices()", test_lwgeom_count_vertices))  ||  
    3939            (NULL == CU_add_test(pSuite, "test_on_gser_lwgeom_count_vertices()", test_on_gser_lwgeom_count_vertices))  || 
    40             (NULL == CU_add_test(pSuite, "test_gbox_calculation()", test_gbox_calculation))   
     40            (NULL == CU_add_test(pSuite, "test_gbox_calculation()", test_gbox_calculation)) || 
     41            (NULL == CU_add_test(pSuite, "test_lwcollection_extract()", test_lwcollection_extract))   
    4142 
    4243        ) 
     
    458459        lwfree(gbox); 
    459460} 
     461 
     462void test_lwcollection_extract(void) 
     463{ 
     464 
     465        LWGEOM *geom; 
     466        LWCOLLECTION *col; 
     467         
     468        geom = lwgeom_from_ewkt("GEOMETRYCOLLECTION(POINT(0 0))", PARSER_CHECK_NONE); 
     469        col = lwcollection_extract((LWCOLLECTION*)geom, 1); 
     470        CU_ASSERT_EQUAL(TYPE_GETTYPE(col->type), MULTIPOINTTYPE); 
     471 
     472        lwcollection_release(col); 
     473        lwgeom_free(geom); 
     474         
     475} 
  • trunk/liblwgeom/cunit/cu_libgeom.h

    r4537 r4847  
    3838void test_gbox_serialized_size(void); 
    3939void test_gbox_calculation(void); 
     40void test_lwcollection_extract(void); 
  • trunk/liblwgeom/liblwgeom.h

    r4710 r4847  
    917917LWGEOM *lwcollection_getsubgeom(LWCOLLECTION *col, int gnum); 
    918918BOX3D *lwcollection_compute_box3d(LWCOLLECTION *col); 
    919  
     919LWCOLLECTION* lwcollection_extract(LWCOLLECTION *col, int type); 
    920920 
    921921/****************************************************************** 
  • trunk/liblwgeom/lwcollection.c

    r4789 r4847  
    558558        return boxfinal; 
    559559} 
     560 
     561/** 
     562* Takes a potentially heterogeneous collection and returns a homogeneous 
     563* collection consisting only of the specified type. 
     564*/ 
     565LWCOLLECTION* lwcollection_extract(LWCOLLECTION *col, int type) 
     566{ 
     567        int i = 0; 
     568        LWGEOM **geomlist; 
     569        BOX3D *b3d; 
     570        LWCOLLECTION *outcol; 
     571        int geomlistsize = 16; 
     572        int geomlistlen = 0; 
     573        uchar outtype; 
     574 
     575        if( ! col ) return NULL; 
     576 
     577        switch (type) 
     578        { 
     579                case POINTTYPE: 
     580                        outtype = MULTIPOINTTYPE; 
     581                        break; 
     582                case LINETYPE: 
     583                        outtype = MULTILINETYPE; 
     584                        break; 
     585                case POLYGONTYPE: 
     586                        outtype = MULTIPOLYGONTYPE; 
     587                        break; 
     588                default: 
     589                        lwerror("Only POLYGON, LINESTRING and POINT are supported by lwcollection_extract. %s requested.", lwgeom_typename(type)); 
     590                        return NULL; 
     591        } 
     592         
     593        geomlist = lwalloc(sizeof(LWGEOM*) * geomlistsize); 
     594 
     595        /* Process each sub-geometry */ 
     596        for( i = 0; i < col->ngeoms; i++ ) 
     597        { 
     598                int subtype = TYPE_GETTYPE(col->geoms[i]->type); 
     599                /* Copy our sub-types into the output list */ 
     600                if( subtype == type ) 
     601                { 
     602                        /* We've over-run our buffer, double the memory segment */ 
     603                        if( geomlistlen == geomlistsize ) 
     604                        { 
     605                                geomlistsize *= 2; 
     606                                geomlist = lwrealloc(geomlist, sizeof(LWGEOM*) * geomlistsize); 
     607                        } 
     608                        geomlist[geomlistlen] = col->geoms[i]; 
     609                        geomlistlen++; 
     610                } 
     611                if( lwgeom_is_collection( subtype ) ) 
     612                { 
     613                        int j = 0; 
     614                        LWCOLLECTION *tmpcol = lwcollection_extract((LWCOLLECTION*)col->geoms[i], type); 
     615                        for( j = 0; j < tmpcol->ngeoms; j++ ) 
     616                        { 
     617                                /* We've over-run our buffer, double the memory segment */ 
     618                                if( geomlistlen == geomlistsize ) 
     619                                { 
     620                                        geomlistsize *= 2; 
     621                                        geomlist = lwrealloc(geomlist, sizeof(LWGEOM*) * geomlistsize); 
     622                                } 
     623                                geomlist[geomlistlen] = tmpcol->geoms[j]; 
     624                                geomlistlen++; 
     625                        } 
     626                        lwfree(tmpcol); 
     627                } 
     628        } 
     629         
     630        if( geomlistlen > 0 ) 
     631        { 
     632                outcol = lwcollection_construct(outtype, col->SRID, NULL, geomlistlen, geomlist);        
     633                b3d = lwcollection_compute_box3d(outcol); 
     634                outcol->bbox = box3d_to_box2df(b3d); 
     635        } 
     636        else 
     637        { 
     638                outcol = lwcollection_construct_empty(col->SRID, TYPE_HASZ(col->type), TYPE_HASM(col->type)); 
     639        } 
     640         
     641        return outcol; 
     642} 
     643 
  • trunk/liblwgeom/lwutil.c

    r4494 r4847  
    208208 
    209209 
    210 const char * 
    211 lwgeom_typename(int type) 
     210const char* lwgeom_typename(int type) 
    212211{ 
    213212        /* something went wrong somewhere */ 
  • trunk/postgis/lwgeom_functions_basic.c

    r4831 r4847  
    7979Datum ST_GeoHash(PG_FUNCTION_ARGS); 
    8080Datum ST_MakeEnvelope(PG_FUNCTION_ARGS); 
     81Datum ST_CollectionExtract(PG_FUNCTION_ARGS); 
    8182 
    8283void lwgeom_affine_ptarray(POINTARRAY *pa, double afac, double bfac, double cfac, 
     
    34363437 
    34373438} 
     3439 
     3440PG_FUNCTION_INFO_V1(ST_CollectionExtract); 
     3441Datum ST_CollectionExtract(PG_FUNCTION_ARGS) 
     3442{ 
     3443        PG_LWGEOM *input = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); 
     3444        PG_LWGEOM *output; 
     3445        LWGEOM *lwgeom = pglwgeom_deserialize(input); 
     3446        LWCOLLECTION *lwcol = NULL; 
     3447        int type = PG_GETARG_INT32(1); 
     3448        int lwgeom_type = TYPE_GETTYPE(lwgeom->type); 
     3449         
     3450        /* Ensure the right type was input */ 
     3451        if ( ! ( type == POINTTYPE || type == LINETYPE || type == POLYGONTYPE ) ) 
     3452        { 
     3453                lwgeom_free(lwgeom); 
     3454                elog(ERROR, "ST_CollectionExtract: only point, linestring and polygon may be extracted"); 
     3455                PG_RETURN_NULL(); 
     3456        } 
     3457         
     3458        /* Mirror non-collections right back */ 
     3459        if ( ! lwgeom_is_collection(lwgeom_type) ) 
     3460        { 
     3461                output = palloc(VARSIZE(input)); 
     3462                memcpy(VARDATA(output), VARDATA(input), VARSIZE(input) - VARHDRSZ); 
     3463                SET_VARSIZE(output, VARSIZE(input)); 
     3464                lwgeom_free(lwgeom); 
     3465                PG_RETURN_POINTER(output); 
     3466        } 
     3467 
     3468        lwcol = lwcollection_extract((LWCOLLECTION*)lwgeom, type); 
     3469        output = pglwgeom_serialize((LWGEOM*)lwcol); 
     3470        lwgeom_free(lwgeom);  
     3471 
     3472        PG_RETURN_POINTER(output); 
     3473} 
  • trunk/postgis/postgis.sql.in.c

    r4836 r4847  
    14371437        RETURNS geometry 
    14381438        AS 'MODULE_PATHNAME', 'LWGEOM_force_collection' 
     1439        LANGUAGE 'C' IMMUTABLE STRICT; 
     1440 
     1441-- Availability: 1.5.0 
     1442CREATE OR REPLACE FUNCTION ST_CollectionExtract(geometry, integer) 
     1443        RETURNS geometry 
     1444        AS 'MODULE_PATHNAME', 'ST_CollectionExtract' 
    14391445        LANGUAGE 'C' IMMUTABLE STRICT; 
    14401446 
  • trunk/regress/regress_expected

    r4832 r4847  
    198198151|0103000020E61000000100000005000000000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F000000000000F03F000000000000000000000000000000000000000000000000 
    199199152|4326 
     200153|MULTIPOINT(0 0) 
     201154|MULTIPOINT(0 0) 
     202155|MULTIPOINT(0 0,1 1) 
     203156|MULTIPOINT(1 1) 
     204157|MULTILINESTRING((0 0,1 1)) 
     205158|MULTILINESTRING((0 0,1 1),(2 2,3 3)) 
     206159|GEOMETRYCOLLECTION EMPTY 
     207160|MULTIPOINT(1 1) 
     208161|MULTILINESTRING((0 0,1 1),(2 2,3 3)) 
  • trunk/regress/regress.sql

    r4832 r4847  
    278278select '152', ST_SRID(ST_MakeEnvelope(0, 0, 1, 1, 4326)); 
    279279 
     280select '153', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(POINT(0 0))',1)); 
     281select '154', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0)))',1)); 
     282select '155', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0), POINT(1 1)))',1)); 
     283select '156', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)))',1)); 
     284select '157', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)))',2)); 
     285select '158', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',2)); 
     286select '159', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',3)); 
     287select '160', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',1)); 
     288select '161', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), GEOMETRYCOLLECTION(POINT(1 1))),LINESTRING(2 2, 3 3))',2)); 
     289 
    280290 
    281291-- Drop test table