[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