[postgis-users] X() function working for POINTs and MULTIPOINTs
Bernhard Reimar Hoefle
Bernhard.Hoefle at uibk.ac.at
Mon Mar 20 08:13:13 PST 2006
Hi!
I wanted to mix POINT and MULTIPOINTs in one geometry column. I know that it is
not the most elegant way but for my purpose the best solution concerning
performance and disk storage.
I wanted to get the coordinates (x,y,z) for each row.
The PostGIS x() function does not support MULTIPOINTs and the geometryN() does
not support POINTs.
select x('MULTIPOINT(1 1 1,2 2 2)'::GEOMETRY);
ERROR: Argument to X() must be a point
ERROR: Argument to X() must be a point
select x(geometryn('POINT(2 2 2)'::GEOMETRY,1));
x
---
(1 row)
Hence, a simple SQL statement to extract coordinates from mixed types is not
possible.
Therefore I modified the X() function to X(geometry,int) which works for both
types.
Maybe it's interesting for someone working with the same 'dirty' solution.
Added lines in lwgeom_ogc.c:
##############################
Datum LWGEOM_xx_point(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(LWGEOM_xx_point);
Datum LWGEOM_xx_point(PG_FUNCTION_ARGS)
{
PG_LWGEOM *geom;
LWPOINT *point = NULL;
POINT2D p;
int idx = PG_GETARG_INT32(1);
LWCOLLECTION *coll;
LWGEOM *subgeom;
geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
if ( TYPE_GETTYPE(geom->type) == POINTTYPE )
{
point = lwgeom_getpoint(SERIALIZED_FORM(geom), 0);
getPoint2d_p(point->point, 0, &p);
PG_FREE_IF_COPY(geom, 0);
PG_RETURN_FLOAT8(p.x);
}
else if ( TYPE_GETTYPE(geom->type) == MULTIPOINTTYPE )
{
idx -= 1; /* index is 1-based */
coll = (LWCOLLECTION *)lwgeom_deserialize(SERIALIZED_FORM(geom));
if ( idx < 0 ) PG_RETURN_NULL();
if ( idx >= coll->ngeoms ) PG_RETURN_NULL();
subgeom = coll->geoms[idx];
/* Construct an LWPOINT */
point = lwgeom_as_lwpoint(subgeom);
getPoint2d_p(point->point, 0, &p);
lwgeom_release((LWGEOM *)coll);
PG_FREE_IF_COPY(geom, 0);
PG_RETURN_FLOAT8(p.x);
}
else
lwerror("First argument to x(geometry,integer) must be a point or multipoint
object");
}
Added lines in lwpostgis.sql:
#############################
CREATE OR REPLACE FUNCTION X(geometry, integer)
RETURNS float8
AS '$libdir/liblwgeom.so.1.1','LWGEOM_xx_point'
LANGUAGE 'C' IMMUTABLE STRICT; -- WITH (isstrict);
The same procedure can be done for Y(), Z().
It was my first attempt in programming with C. I hope the C code is ok?
Better solutions and suggestions are welcome.
Bernhard
More information about the postgis-users
mailing list