[postgis-devel] ST_isValidDetail

strk strk at keybit.net
Fri Feb 5 08:26:01 PST 2010


Attached is a patch which implements ST_isValidDetail(geometry)
returns valid_detail(valid bool, reason varchar, location geometry).

The location is always a point (if anything).
The reason is blank if valid is true.

Dare to check on pgsql < 8.3 and GEOS < 3.3.0 (trunk) ?
Also, I might be missing some upgrade thingies (I just
touched postgis.sql.in.c)

Oh, let me know if I should just commit rather than ask 
to ask to test to check ... :)

--strk; 

  ()   Free GIS & Flash consultant/developer
  /\   http://foo.keybit.net/~strk/services.html
-------------- next part --------------
Index: postgis/lwgeom_geos.c
===================================================================
--- postgis/lwgeom_geos.c	(revision 5203)
+++ postgis/lwgeom_geos.c	(working copy)
@@ -16,6 +16,7 @@
 #include "lwgeom_geos.h"
 #include "lwgeom_rtree.h"
 #include "lwgeom_geos_prepared.h"
+#include "funcapi.h"
 
 #include <string.h>
 
@@ -42,6 +43,7 @@
 Datum overlaps(PG_FUNCTION_ARGS);
 Datum isvalid(PG_FUNCTION_ARGS);
 Datum isvalidreason(PG_FUNCTION_ARGS);
+Datum isvaliddetail(PG_FUNCTION_ARGS);
 Datum buffer(PG_FUNCTION_ARGS);
 Datum intersection(PG_FUNCTION_ARGS);
 Datum convexhull(PG_FUNCTION_ARGS);
@@ -1449,6 +1451,99 @@
 
 }
 
+/*
+** IsValidDetail is only available in the GEOS
+** C API >= version 3.3
+*/
+PG_FUNCTION_INFO_V1(isvaliddetail);
+Datum isvaliddetail(PG_FUNCTION_ARGS)
+{
+#if POSTGIS_GEOS_VERSION < 33
+	lwerror("The GEOS version this postgis binary "
+	        "was compiled against (%d) doesn't support "
+	        "'isValidDetail' function (3.3.0+ required)",
+	        POSTGIS_GEOS_VERSION);
+	PG_RETURN_NULL();
+#else /* POSTGIS_GEOS_VERSION >= 33 */
+
+	PG_LWGEOM *geom = NULL;
+	const GEOSGeometry *g1 = NULL;
+	char *values[3]; /* valid bool, reason text, location geometry */
+	char *geos_reason = NULL;
+	char *reason = NULL;
+	const GEOSGeometry *geos_location = NULL;
+	LWGEOM *location = NULL;
+	char valid;
+	Datum result;
+	TupleDesc tupdesc;
+	HeapTuple tuple;
+	AttInMetadata *attinmeta;
+
+	/*
+	 * Build a tuple description for a
+	 * valid_detail tuple
+	 */
+	tupdesc = RelationNameGetTupleDesc("valid_detail");
+	if ( ! tupdesc )
+	{
+		lwerror("TYPE valid_detail not found");
+		PG_RETURN_NULL();
+	}
+
+	/*
+	 * generate attribute metadata needed later to produce
+	 * tuples from raw C strings
+	 */
+	attinmeta = TupleDescGetAttInMetadata(tupdesc);
+
+	geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+
+	initGEOS(lwnotice, lwnotice);
+
+	g1 = (GEOSGeometry *)POSTGIS2GEOS(geom);
+	if ( ! g1 )
+	{	/* TODO: take as invalid */
+		PG_RETURN_NULL();
+	}
+
+	valid = GEOSisValidDetail(g1, &geos_reason, &geos_location);
+	GEOSGeom_destroy((GEOSGeometry *)g1);
+	if ( geos_reason )
+	{
+		reason = pstrdup(geos_reason);
+		GEOSFree(geos_reason);
+	}
+	if ( geos_location )
+	{
+		location = GEOS2LWGEOM(geos_location, GEOSHasZ(geos_location));
+		GEOSGeom_destroy((GEOSGeometry *)geos_location);
+	}
+
+	if (valid == 2)
+	{
+		/* NOTE: should only happen on OOM or similar */
+		lwerror("GEOS isvaliddetail() threw an exception!");
+		PG_RETURN_NULL(); /* never gets here */
+	}
+
+	/* the boolean validity */
+	values[0] =  valid ? "t" : "f";
+
+	/* the reason */
+	values[1] =  reason;
+
+	/* the location */
+	values[2] =  location ?
+	             lwgeom_to_hexwkb(location, PARSER_CHECK_NONE, -1) : 0;
+
+	tuple = BuildTupleFromCStrings(attinmeta, values);
+	result = HeapTupleGetDatum(tuple);
+
+	PG_RETURN_HEAPTUPLEHEADER(result);
+
+#endif /* POSTGIS_GEOS_VERSION >= 33 */
+}
+
 /**
  * overlaps(PG_LWGEOM g1,PG_LWGEOM g2)
  * @param g1
Index: postgis/postgis.sql.in.c
===================================================================
--- postgis/postgis.sql.in.c	(revision 5203)
+++ postgis/postgis.sql.in.c	(working copy)
@@ -3923,6 +3923,17 @@
 	LANGUAGE 'C' IMMUTABLE STRICT
 	COST 100;
 
+-- Availability: 2.0.0
+CREATE TYPE valid_detail AS (valid bool, reason varchar, location geometry);
+
+-- Requires GEOS >= 3.3.0
+-- Availability: 2.0.0
+CREATE OR REPLACE FUNCTION ST_IsValidDetail(geometry)
+	RETURNS valid_detail
+	AS 'MODULE_PATHNAME', 'isvaliddetail'
+	LANGUAGE 'C' IMMUTABLE STRICT
+	COST 100;
+
 #if POSTGIS_GEOS_VERSION >= 32
 -- Requires GEOS >= 3.2.0
 -- Availability: 1.5.0


More information about the postgis-devel mailing list