</refsection>
</refentry>
+ <refentry id="ST_CollectionExtract">
+ <refnamediv>
+ <refname>ST_CollectionExtract</refname>
+
+ <refpurpose>Given a GEOMETRYCOLLECTION, returns the a MULTI* geometry consisting only the specified type. Sub-geometries that are not
+ the specified type are ignored.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>geometry <function>ST_CollectionExtract</function></funcdef>
+ <paramdef><type>geometry </type> <parameter>collection</parameter></paramdef>
+ <paramdef><type>integer </type> <parameter>type</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+
+ <para>Given a GEOMETRYCOLLECTION, returns the a MULTI* geometry consisting only the specified type. Sub-geometries that are not
+ the specified type are ignored. If there are no sub-geometries of the right type, an EMPTY collection will be returned. Only
+ points, lines and polygons are supported.</para>
+
+ </refsection>
+
+ <refsection>
+ <title>Examples</title>
+
+ <programlisting>SELECT ST_AsText(ST_CollectionExtract(ST_GeomFromText('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0)))'),1));
+ st_astext
+ ---------------
+ MULTIPOINT(0 0)
+ (1 row)
+ </programlisting>
+ </refsection>
+ <refsection>
+ <title>See Also</title>
+ <para><xref linkend="ST_Multi" /></para>
+ </refsection>
+ </refentry>
+
<refentry id="ST_Multi">
<refnamediv>
<refname>ST_Multi</refname>
(NULL == CU_add_test(pSuite, "test_lwgeom_check_geodetic()", test_lwgeom_check_geodetic)) ||
(NULL == CU_add_test(pSuite, "test_lwgeom_count_vertices()", test_lwgeom_count_vertices)) ||
(NULL == CU_add_test(pSuite, "test_on_gser_lwgeom_count_vertices()", test_on_gser_lwgeom_count_vertices)) ||
- (NULL == CU_add_test(pSuite, "test_gbox_calculation()", test_gbox_calculation))
+ (NULL == CU_add_test(pSuite, "test_gbox_calculation()", test_gbox_calculation)) ||
+ (NULL == CU_add_test(pSuite, "test_lwcollection_extract()", test_lwcollection_extract))
)
{
}
lwfree(gbox);
}
+
+void test_lwcollection_extract(void)
+{
+
+ LWGEOM *geom;
+ LWCOLLECTION *col;
+
+ geom = lwgeom_from_ewkt("GEOMETRYCOLLECTION(POINT(0 0))", PARSER_CHECK_NONE);
+ col = lwcollection_extract((LWCOLLECTION*)geom, 1);
+ CU_ASSERT_EQUAL(TYPE_GETTYPE(col->type), MULTIPOINTTYPE);
+
+ lwcollection_release(col);
+ lwgeom_free(geom);
+
+}
void test_on_gser_lwgeom_count_vertices(void);
void test_gbox_serialized_size(void);
void test_gbox_calculation(void);
+void test_lwcollection_extract(void);
LWGEOM *lwcollection_getsubgeom(LWCOLLECTION *col, int gnum);
BOX3D *lwcollection_compute_box3d(LWCOLLECTION *col);
-
+LWCOLLECTION* lwcollection_extract(LWCOLLECTION *col, int type);
/******************************************************************
* SERIALIZED FORM functions
}
return boxfinal;
}
+
+/**
+* Takes a potentially heterogeneous collection and returns a homogeneous
+* collection consisting only of the specified type.
+*/
+LWCOLLECTION* lwcollection_extract(LWCOLLECTION *col, int type)
+{
+ int i = 0;
+ LWGEOM **geomlist;
+ BOX3D *b3d;
+ LWCOLLECTION *outcol;
+ int geomlistsize = 16;
+ int geomlistlen = 0;
+ uchar outtype;
+
+ if( ! col ) return NULL;
+
+ switch (type)
+ {
+ case POINTTYPE:
+ outtype = MULTIPOINTTYPE;
+ break;
+ case LINETYPE:
+ outtype = MULTILINETYPE;
+ break;
+ case POLYGONTYPE:
+ outtype = MULTIPOLYGONTYPE;
+ break;
+ default:
+ lwerror("Only POLYGON, LINESTRING and POINT are supported by lwcollection_extract. %s requested.", lwgeom_typename(type));
+ return NULL;
+ }
+
+ geomlist = lwalloc(sizeof(LWGEOM*) * geomlistsize);
+
+ /* Process each sub-geometry */
+ for( i = 0; i < col->ngeoms; i++ )
+ {
+ int subtype = TYPE_GETTYPE(col->geoms[i]->type);
+ /* Copy our sub-types into the output list */
+ if( subtype == type )
+ {
+ /* We've over-run our buffer, double the memory segment */
+ if( geomlistlen == geomlistsize )
+ {
+ geomlistsize *= 2;
+ geomlist = lwrealloc(geomlist, sizeof(LWGEOM*) * geomlistsize);
+ }
+ geomlist[geomlistlen] = col->geoms[i];
+ geomlistlen++;
+ }
+ if( lwgeom_is_collection( subtype ) )
+ {
+ int j = 0;
+ LWCOLLECTION *tmpcol = lwcollection_extract((LWCOLLECTION*)col->geoms[i], type);
+ for( j = 0; j < tmpcol->ngeoms; j++ )
+ {
+ /* We've over-run our buffer, double the memory segment */
+ if( geomlistlen == geomlistsize )
+ {
+ geomlistsize *= 2;
+ geomlist = lwrealloc(geomlist, sizeof(LWGEOM*) * geomlistsize);
+ }
+ geomlist[geomlistlen] = tmpcol->geoms[j];
+ geomlistlen++;
+ }
+ lwfree(tmpcol);
+ }
+ }
+
+ if( geomlistlen > 0 )
+ {
+ outcol = lwcollection_construct(outtype, col->SRID, NULL, geomlistlen, geomlist);
+ b3d = lwcollection_compute_box3d(outcol);
+ outcol->bbox = box3d_to_box2df(b3d);
+ }
+ else
+ {
+ outcol = lwcollection_construct_empty(col->SRID, TYPE_HASZ(col->type), TYPE_HASM(col->type));
+ }
+
+ return outcol;
+}
+
}
-const char *
-lwgeom_typename(int type)
+const char* lwgeom_typename(int type)
{
/* something went wrong somewhere */
if ( type < 0 || type > 15 )
Datum optimistic_overlap(PG_FUNCTION_ARGS);
Datum ST_GeoHash(PG_FUNCTION_ARGS);
Datum ST_MakeEnvelope(PG_FUNCTION_ARGS);
+Datum ST_CollectionExtract(PG_FUNCTION_ARGS);
void lwgeom_affine_ptarray(POINTARRAY *pa, double afac, double bfac, double cfac,
double dfac, double efac, double ffac, double gfac, double hfac, double ifac, double xoff, double yoff, double zoff);
PG_RETURN_POINTER(result);
}
+
+PG_FUNCTION_INFO_V1(ST_CollectionExtract);
+Datum ST_CollectionExtract(PG_FUNCTION_ARGS)
+{
+ PG_LWGEOM *input = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ PG_LWGEOM *output;
+ LWGEOM *lwgeom = pglwgeom_deserialize(input);
+ LWCOLLECTION *lwcol = NULL;
+ int type = PG_GETARG_INT32(1);
+ int lwgeom_type = TYPE_GETTYPE(lwgeom->type);
+
+ /* Ensure the right type was input */
+ if ( ! ( type == POINTTYPE || type == LINETYPE || type == POLYGONTYPE ) )
+ {
+ lwgeom_free(lwgeom);
+ elog(ERROR, "ST_CollectionExtract: only point, linestring and polygon may be extracted");
+ PG_RETURN_NULL();
+ }
+
+ /* Mirror non-collections right back */
+ if ( ! lwgeom_is_collection(lwgeom_type) )
+ {
+ output = palloc(VARSIZE(input));
+ memcpy(VARDATA(output), VARDATA(input), VARSIZE(input) - VARHDRSZ);
+ SET_VARSIZE(output, VARSIZE(input));
+ lwgeom_free(lwgeom);
+ PG_RETURN_POINTER(output);
+ }
+
+ lwcol = lwcollection_extract((LWCOLLECTION*)lwgeom, type);
+ output = pglwgeom_serialize((LWGEOM*)lwcol);
+ lwgeom_free(lwgeom);
+
+ PG_RETURN_POINTER(output);
+}
\ No newline at end of file
AS 'MODULE_PATHNAME', 'LWGEOM_force_collection'
LANGUAGE 'C' IMMUTABLE STRICT;
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_CollectionExtract(geometry, integer)
+ RETURNS geometry
+ AS 'MODULE_PATHNAME', 'ST_CollectionExtract'
+ LANGUAGE 'C' IMMUTABLE STRICT;
+
-- Deprecation in 1.2.3
CREATE OR REPLACE FUNCTION multi(geometry)
RETURNS geometry
select '151', ST_MakeEnvelope(0, 0, 1, 1, 4326);
select '152', ST_SRID(ST_MakeEnvelope(0, 0, 1, 1, 4326));
+select '153', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(POINT(0 0))',1));
+select '154', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0)))',1));
+select '155', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(0 0), POINT(1 1)))',1));
+select '156', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)))',1));
+select '157', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)))',2));
+select '158', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',2));
+select '159', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',3));
+select '160', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), POINT(1 1)),LINESTRING(2 2, 3 3))',1));
+select '161', ST_AsText(ST_CollectionExtract('GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(LINESTRING(0 0, 1 1), GEOMETRYCOLLECTION(POINT(1 1))),LINESTRING(2 2, 3 3))',2));
+
-- Drop test table
DROP table test;
150_|SRID=6;GEOMETRYCOLLECTION(POLYGON((0 0,1 0,1 1,0 1,0 0)))
151|0103000020E61000000100000005000000000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F000000000000F03F000000000000000000000000000000000000000000000000
152|4326
+153|MULTIPOINT(0 0)
+154|MULTIPOINT(0 0)
+155|MULTIPOINT(0 0,1 1)
+156|MULTIPOINT(1 1)
+157|MULTILINESTRING((0 0,1 1))
+158|MULTILINESTRING((0 0,1 1),(2 2,3 3))
+159|GEOMETRYCOLLECTION EMPTY
+160|MULTIPOINT(1 1)
+161|MULTILINESTRING((0 0,1 1),(2 2,3 3))